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/SignedDataDemo.java 35    12.02.25 17:58 Dbratko $
059    // $Revision: 35 $
060    //
061    
062    package demo.cms.signedData;
063    
064    import iaik.asn1.ASN1Object;
065    import iaik.asn1.ObjectID;
066    import iaik.asn1.SEQUENCE;
067    import iaik.asn1.UTF8String;
068    import iaik.asn1.structures.AlgorithmID;
069    import iaik.asn1.structures.Attribute;
070    import iaik.asn1.structures.GeneralName;
071    import iaik.asn1.structures.GeneralNames;
072    import iaik.asn1.structures.Name;
073    import iaik.asn1.structures.PolicyInformation;
074    import iaik.asn1.structures.PolicyQualifierInfo;
075    import iaik.cms.CMSException;
076    import iaik.cms.ContentInfo;
077    import iaik.cms.ContentInfoStream;
078    import iaik.cms.IssuerAndSerialNumber;
079    import iaik.cms.SignedData;
080    import iaik.cms.SignedDataStream;
081    import iaik.cms.SignerInfo;
082    import iaik.cms.SubjectKeyID;
083    import iaik.cms.attributes.CMSContentType;
084    import iaik.cms.attributes.SigningTime;
085    import iaik.smime.ess.SigningCertificate;
086    import iaik.smime.ess.SigningCertificateV2;
087    import iaik.utils.Util;
088    import iaik.x509.X509Certificate;
089    import iaik.x509.X509ExtensionException;
090    import iaik.x509.attr.AttributeCertificate;
091    import iaik.x509.attr.Holder;
092    import iaik.x509.attr.V2Form;
093    
094    import java.io.ByteArrayInputStream;
095    import java.io.ByteArrayOutputStream;
096    import java.io.IOException;
097    import java.io.InputStream;
098    import java.math.BigInteger;
099    import java.security.NoSuchAlgorithmException;
100    import java.security.PrivateKey;
101    import java.security.SignatureException;
102    import java.security.cert.Certificate;
103    import java.util.Calendar;
104    import java.util.Date;
105    import java.util.GregorianCalendar;
106    
107    import demo.DemoUtil;
108    import demo.keystore.CMSKeyStore;
109    
110    
111    /**
112     * Demonstrates the usage of class {@link iaik.cms.SignedDataStream} and
113     * {@link iaik.cms.SignedData} for signing some data using the CMS type
114     * SignedData.
115     */
116    public class SignedDataDemo {
117    
118      // certificate of user 1
119      X509Certificate user1Cert_;
120      // private key of user 1
121      PrivateKey user1PrivKey_;
122      // certificate of user 2
123      X509Certificate user2Cert_;
124      // private key of user 2
125      PrivateKey user2PrivKey_;
126    
127      // a certificate array containing the user certs + CA certs
128      Certificate[] certificates_;
129    
130      // a certificate array containing the certificates of user1 and an attribute certificate
131      Certificate[] certs_;
132      
133      /**
134       * Setups the demo certificate chains.
135       * 
136       * Keys and certificate are retrieved from the demo KeyStore.
137       * 
138       * @throws IOException if an file read error occurs
139       */
140      public SignedDataDemo() throws IOException {
141        
142        System.out.println();
143        System.out.println("**********************************************************************************");
144        System.out.println("*                             SignedDataDemo                                     *");
145        System.out.println("*          (shows the usage of the CMS SignedData type implementation)           *");
146        System.out.println("**********************************************************************************");
147        System.out.println();
148        
149        // add all certificates to the list
150        X509Certificate[] user1Certs = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
151        user1Cert_ = (X509Certificate)user1Certs[0];
152        user1PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
153        X509Certificate[] user2Certs = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_1024_SIGN);
154        user2Cert_ = user2Certs[0];
155        user2PrivKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_1024_SIGN);
156        
157        // certs_ contains the certificate chain of user1 and an attribute certificate
158        certs_ = user1Certs;
159        try {
160          AttributeCertificate attrCert = createAttributeCertificate();
161          certs_ = new Certificate[user1Certs.length+1];  
162          System.arraycopy(user1Certs, 0, certs_, 0, user1Certs.length);
163          certs_[user1Certs.length] = attrCert;
164        } catch (CMSException ex) {
165          System.out.println("No attribute certificates!");   
166        }    
167        
168        // certificates_ contains the chains of user1 and user2 and an attribute certificate
169        certificates_ = new Certificate[certs_.length + user2Certs.length];
170        System.arraycopy(certs_, 0, certificates_, 0, certs_.length);
171        System.arraycopy(user2Certs, 0, certificates_, certs_.length, user2Certs.length);
172      }
173      
174      /**
175       * Creates a CMS <code>SignedData</code> object.
176       * <p>
177       *
178       * @param message the message to be signed, as byte representation
179       * @param mode the transmission mode, either IMPLICIT or EXPLICIT
180       * @return the BER encoding of the <code>SignedData</code> object just created
181       * @throws CMSException if the <code>SignedData</code> object cannot
182       *                          be created
183       * @throws IOException if some stream I/O error occurs
184       */
185      public byte[] createSignedDataStream(byte[] message, int mode) throws CMSException, IOException  {
186        
187        System.out.print("Create a new message signed by user 1 :");
188       
189        // we are testing the stream interface
190        ByteArrayInputStream is = new ByteArrayInputStream(message);
191        // create a new SignedData object which includes the data
192        SignedDataStream signedData = new SignedDataStream(is, mode);
193        
194        // SignedData shall include the certificate chain for verifying
195        signedData.setCertificates(certificates_);
196        
197        // cert at index 0 is the user certificate
198        IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1Cert_);
199    
200        // create a new SignerInfo
201        SignerInfo signerInfo = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), user1PrivKey_);
202        // create some authenticated attributes
203        // the message digest attribute is automatically added
204        Attribute[] attributes = new Attribute[3];
205        try {
206          // content type is data
207          CMSContentType contentType = new CMSContentType(ObjectID.cms_data);
208          attributes[0] = new Attribute(contentType);
209          // signing time is now
210          SigningTime signingTime = new SigningTime();
211          attributes[1] = new Attribute(signingTime);
212          // signing certificate
213          SigningCertificateV2 signingCertificate = new SigningCertificateV2(certs_);
214          String explicitText = "This certificate only may be used for test purposes";
215          PolicyQualifierInfo policyQualifier = new PolicyQualifierInfo(null, null, explicitText);
216          PolicyInformation[] policyInformations = 
217            { new PolicyInformation(new ObjectID("1.3.6.1.4.1.2706.17.0.11.1.1"),
218                                  new PolicyQualifierInfo[] { policyQualifier }) };
219          //signingCertificate.setPolicies(policyInformations);                        
220          System.out.println("Include signingCertificate attribute:");
221          System.out.println(signingCertificate);
222          attributes[2] = new Attribute(signingCertificate);
223        } catch (Exception ex) {
224          throw new CMSException("Error creating attribute: " + ex.toString());   
225        }    
226        // set the attributes
227        signerInfo.setSignedAttributes(attributes);
228        // finish the creation of SignerInfo by calling method addSigner
229        try {
230          signedData.addSignerInfo(signerInfo);
231          // another SignerInfo without signed attributes 
232          signerInfo = new SignerInfo(new SubjectKeyID(user2Cert_), 
233                                       (AlgorithmID)AlgorithmID.sha1.clone(),
234                                       (AlgorithmID)AlgorithmID.dsaWithSHA.clone(),
235                                       user2PrivKey_);
236          
237          // the message digest itself is protected
238          signedData.addSignerInfo(signerInfo);
239    
240        } catch (NoSuchAlgorithmException ex) {
241          throw new CMSException(ex.toString());
242        } catch (X509ExtensionException ex) {
243          throw new CMSException("Cannot create SubjectKeyID for user2 : " + ex.getMessage());
244        }
245    
246        // write the data through SignedData to any out-of-band place
247        if (mode == SignedDataStream.EXPLICIT) {
248          InputStream data_is = signedData.getInputStream();
249          byte[] buf = new byte[1024];
250          int r;
251          while ((r = data_is.read(buf)) > 0) {
252            ;   // skip data
253          }   
254        }
255    
256        // return the SignedData as DER encoded byte array with block size 2048
257        ByteArrayOutputStream os = new ByteArrayOutputStream();
258        signedData.setBlockSize(2048);
259        ContentInfoStream cis = new ContentInfoStream(signedData);
260        cis.writeTo(os);
261        return os.toByteArray();
262      }
263      
264    
265      /**
266       * Parses a CMS <code>SignedData</code> object and verifies the signatures
267       * for all participated signers.
268       *
269       * @param signedDataEnc <code>SignedData</code> object as BER encoded byte array
270       * @param message the the message which was transmitted out-of-band (explicit signed)
271       *
272       * @return the inherent message as byte array
273       * @throws CMSException if any signature does not verify
274       * @throws IOException if some stream I/O error occurs
275       */
276      public byte[] getSignedDataStream(byte[] signedDataEnc, byte[] message) throws CMSException, IOException {
277    
278        // we are testing the stream interface
279        ByteArrayInputStream is = new ByteArrayInputStream(signedDataEnc);
280        // create the SignedData object
281        SignedDataStream signedData = new SignedDataStream(is);
282        
283        if (signedData.getMode() == SignedDataStream.EXPLICIT) {
284          // in explicit mode explicitly supply the content for hash computation  
285          signedData.setInputStream(new ByteArrayInputStream(message));
286        }
287    
288        // get an InputStream for reading the signed content
289        InputStream data = signedData.getInputStream();
290        ByteArrayOutputStream os = new ByteArrayOutputStream();
291        Util.copyStream(data, os, null);
292        
293        System.out.println("SignedData contains the following signer information:");
294        SignerInfo[] signer_infos = signedData.getSignerInfos();
295        
296        int numberOfSignerInfos = signer_infos.length;
297        if (numberOfSignerInfos == 0) {
298          String warning = "Warning: Unsigned message (no SignerInfo included)!";  
299          System.err.println(warning);
300          throw new CMSException(warning);
301        } else {
302          for (int i = 0; i < numberOfSignerInfos; i++) {
303            
304            try {
305              // verify the signed data using the SignerInfo at index i
306              X509Certificate signer_cert = signedData.verify(i);
307              // if the signature is OK the certificate of the signer is returned
308              System.out.println("Signature OK from signer: "+signer_cert.getSubjectDN());
309              SigningTime signingTime = (SigningTime)signer_infos[i].getSignedAttributeValue(ObjectID.signingTime);
310              if (signingTime != null) {
311                System.out.println("This message has been signed at " + signingTime.get());
312              } 
313              CMSContentType contentType = (CMSContentType)signer_infos[i].getSignedAttributeValue(ObjectID.contentType);
314              if (contentType != null) {
315                System.out.println("The content has CMS content type " + contentType.get().getName());
316              }
317              // check SigningCertificate attribute
318              try {
319                SigningCertificate signingCertificate = signer_infos[i].getSigningCertificateAttribute();
320                if (signingCertificate != null) {
321                  checkSigningCertificate(signingCertificate, signer_cert, signedData, i);  
322                }  
323              } catch (CMSException ex) {
324                throw new CMSException("Error parsing SigningCertificate attribute: " + ex.getMessage());   
325              }    
326             
327            } catch (SignatureException ex) {
328              // if the signature is not OK a SignatureException is thrown
329              System.out.println("Signature ERROR from signer: "+signedData.getCertificate(signer_infos[i].getSignerIdentifier()).getSubjectDN());
330              throw new CMSException(ex.toString());
331            }  
332          }  
333          
334          // now check alternative signature verification
335          System.out.println("Now check the signature assuming that no certs have been included:");
336          try {
337             SignerInfo signerInfo = signedData.verify(user1Cert_);
338              // if the signature is OK the certificate of the signer is returned
339              System.out.println("Signature OK from signer: "+user1Cert_.getSubjectDN());
340              
341          } catch (SignatureException ex) {
342              // if the signature is not OK a SignatureException is thrown
343              System.out.println("Signature ERROR from signer: "+user1Cert_.getSubjectDN());
344              throw new CMSException(ex.toString());
345          }
346        
347          System.out.println("Included attribute certificates:");
348          AttributeCertificate[] attributeCerts = signedData.getAttributeCertificates();
349          if (attributeCerts == null) {
350            System.out.println("No attribute certificates");   
351          } else {   
352            for (int i = 0; i < attributeCerts.length; i++) {
353              System.out.println(attributeCerts[i].getHolder());   
354            } 
355          } 
356         
357          try {
358            SignerInfo signerInfo = signedData.verify(user2Cert_);
359            // if the signature is OK the certificate of the signer is returned
360            System.out.println("Signature OK from signer: "+signedData.getCertificate(signerInfo.getSignerIdentifier()).getSubjectDN());
361              
362          } catch (SignatureException ex) {
363            // if the signature is not OK a SignatureException is thrown
364            System.out.println("Signature ERROR from signer: "+user2Cert_.getSubjectDN());
365            throw new CMSException(ex.toString());
366          }
367          // in practice we also would validate the signer certificate(s)  
368        }
369            
370        return os.toByteArray();
371      }
372      
373      
374      
375      /**
376       * Creates a CMS <code>SignedData</code> object.
377       * <p>
378       *
379       * @param message the message to be signed, as byte representation
380       * @param mode the mode, either SignedData.IMPLICIT or SignedData.EXPLICIT
381       * @return the DER encoded <code>SignedData</code> object
382       * @throws CMSException if the <code>SignedData</code> object cannot
383       *                          be created
384       */
385      public byte[] createSignedData(byte[] message, int mode) throws CMSException {
386        
387        System.out.println("Create a new message signed by user 1 :");
388      
389        // create a new SignedData object which includes the data
390        SignedData signedData = new SignedData(message, mode);
391        
392        // SignedData shall include the certificate chain for verifying
393        signedData.setCertificates(certificates_);
394      
395        // cert at index 0 is the user certificate
396        IssuerAndSerialNumber issuer = new IssuerAndSerialNumber(user1Cert_);
397    
398        // create a new SignerInfo
399        SignerInfo signerInfo = new SignerInfo(issuer, (AlgorithmID)AlgorithmID.sha256.clone(), user1PrivKey_);
400        // create some authenticated attributes
401        // the message digest attribute is automatically added
402        Attribute[] attributes = new Attribute[3];
403        try {
404          // content type is data
405          CMSContentType contentType = new CMSContentType(ObjectID.cms_data);
406          attributes[0] = new Attribute(contentType);
407          // signing time is now
408          SigningTime signingTime = new SigningTime();
409          attributes[1] = new Attribute(signingTime);
410          // signing certificate
411          SigningCertificate signingCertificate = new SigningCertificate(certs_);
412          System.out.println("Include signingCertificate attribute:");
413          System.out.println(signingCertificate);
414          attributes[2] = new Attribute(signingCertificate);
415        } catch (Exception ex) {
416          throw new CMSException("Error creating attribute: " + ex.toString());   
417        }    
418        // set the attributes
419        signerInfo.setSignedAttributes(attributes);
420        // finish the creation of SignerInfo by calling method addSigner
421        try {
422          signedData.addSignerInfo(signerInfo);
423    
424          // another SignerInfo without signed attributes 
425          signerInfo = new SignerInfo(new SubjectKeyID(user2Cert_), 
426                                       (AlgorithmID)AlgorithmID.sha1.clone(),
427                                       (AlgorithmID)AlgorithmID.dsaWithSHA.clone(),
428                                       user2PrivKey_);
429      
430          signedData.addSignerInfo(signerInfo);
431    
432        } catch (NoSuchAlgorithmException ex) {
433          throw new CMSException(ex.toString());
434        } catch (X509ExtensionException ex) {
435          throw new CMSException("Cannot create SubjectKeyID for user2 : " + ex.getMessage());
436        }    
437        ContentInfo contentInfo = new ContentInfo(signedData);
438        return contentInfo.getEncoded();
439      }
440      
441      
442      /**
443       * Parses a CMS <code>SignedData</code> object and verifies the signatures
444       * for all participated signers.
445       *
446       * @param encoding the DER encoded <code>SignedData</code> object
447       * @param message the the message which was transmitted out-of-band (explicit signed)
448       *
449       * @return the inherent message as byte array
450       * @throws CMSException if any signature does not verify
451       * @throws IOException if some stream I/O error occurs
452       */
453      public byte[] getSignedData(byte[] encoding, byte[] message) throws CMSException, IOException {
454        
455        ByteArrayInputStream encodedStream = new ByteArrayInputStream(encoding);
456        // create the SignedData object
457        SignedData signedData = new SignedData(encodedStream);
458        
459        if (signedData.getMode() == SignedData.EXPLICIT) {
460          // in explcit mode explictly supply the content data to do the hash calculation
461          signedData.setContent(message);
462        }
463        
464        System.out.println("SignedData contains the following signer information:");
465        SignerInfo[] signerInfos = signedData.getSignerInfos();
466        
467        int numberOfSignerInfos = signerInfos.length;
468        if (numberOfSignerInfos == 0) {
469          String warning = "Warning: Unsigned message (no SignerInfo included)!";  
470          System.err.println(warning);
471          throw new CMSException(warning);
472        } else {
473          for (int i = 0; i < numberOfSignerInfos; i++) {
474            try {
475              // verify the signed data using the SignerInfo at index i
476              X509Certificate signerCert = signedData.verify(i);
477              // if the signature is OK the certificate of the signer is returned
478              System.out.println("Signature OK from signer: "+signerCert.getSubjectDN());
479              SigningTime signingTime = (SigningTime)signerInfos[i].getSignedAttributeValue(ObjectID.signingTime);
480              if (signingTime != null) {
481                System.out.println("This message has been signed at " + signingTime.get());
482              } 
483              CMSContentType contentType = (CMSContentType)signerInfos[i].getSignedAttributeValue(ObjectID.contentType);
484              if (contentType != null) {
485                System.out.println("The content has CMS content type " + contentType.get().getName());
486              }
487              // check SigningCertificate attribute
488              SigningCertificate signingCertificate = signerInfos[i].getSigningCertificateAttribute();
489              if (signingCertificate != null) {
490                checkSigningCertificate(signingCertificate, signerCert, signedData, i);
491              }
492            } catch (SignatureException ex) {
493               // if the signature is not OK a SignatureException is thrown
494               System.out.println("Signature ERROR from signer: "+signedData.getCertificate(signerInfos[i].getSignerIdentifier()).getSubjectDN());
495               throw new CMSException(ex.toString());
496            } 
497          }      
498        
499          // now check alternative signature verification
500          System.out.println("Now check the signature assuming that no certs have been included:");
501          try {
502            SignerInfo signerInfo = signedData.verify(user1Cert_);
503            // if the signature is OK the certificate of the signer is returned
504            System.out.println("Signature OK from signer: "+signedData.getCertificate(signerInfo.getSignerIdentifier()).getSubjectDN());
505              
506          } catch (SignatureException ex) {
507            // if the signature is not OK a SignatureException is thrown
508            System.out.println("Signature ERROR from signer: "+user1Cert_.getSubjectDN());
509            throw new CMSException(ex.toString());
510          }
511          try {
512            SignerInfo signerInfo = signedData.verify(user2Cert_);
513            // if the signature is OK the certificate of the signer is returned
514            System.out.println("Signature OK from signer: "+signedData.getCertificate(signerInfo.getSignerIdentifier()).getSubjectDN());
515              
516          } catch (SignatureException ex) {
517            // if the signature is not OK a SignatureException is thrown
518            System.out.println("Signature ERROR from signer: "+user2Cert_.getSubjectDN());
519            throw new CMSException(ex.toString());
520          }
521          // in practice we also would validate the signer certificate(s)  
522        }
523        return signedData.getContent();
524      }
525      
526      /**
527       * Checks the SigningCertificate attribute.
528       *
529       * @param signingCertificate the SigningCertificate attribute
530       * @param signerCert the certificate of the signer
531       * @param signedData the SignedData containing the SignerInfo with the SigningCertificate
532       *                   attribute to be checked
533       * @param signerInfoIndex the index of the SignerInfo with the SigningCertificate
534       *                   attribute to be checked
535       *
536       * @throws CMSException if the SigningCertificate check fails
537       */
538      private void checkSigningCertificate(SigningCertificate signingCertificate,
539                                           X509Certificate signerCert,
540                                           SignedDataStream signedData,
541                                           int signerInfoIndex) throws CMSException {
542          if (signedData.getSignerInfos()[signerInfoIndex].isSignerCertificate(signerCert) == false) {
543            throw new CMSException("Cert ERROR!!! The certificate used for signing is not the one " +
544                                   "identified by the SignerCertificate attribute!");
545          } else {
546            System.out.println("SigningCertificate attribute: Signer cert ok!");   
547          } 
548          if (signingCertificate != null) {
549            // get the authorization certs for this signerInfo
550            Certificate[] authCerts = 
551              signingCertificate.getAuthorizedCertificates(signedData.getCertificates());
552            if (authCerts != null) {
553              System.out.println("SignedData contains the following authorization certs for SignerInfo No " + (signerInfoIndex+1) +":");   
554              for (int j = 0; j < authCerts.length; j++) {
555                if (authCerts[j].getType().equalsIgnoreCase("X.509")) {
556                  System.out.println("X.509 public key cert: " + ((X509Certificate)authCerts[j]).getSubjectDN());
557                } else {
558                  System.out.println("X.509 attribute cert: " + ((AttributeCertificate)authCerts[j]).getHolder());  
559                }     
560              }  
561            } 
562            if (signingCertificate.countPolicies() > 0) {
563              // get the certs with PolicyInformations according to the SigningCertificate attribute:
564              Certificate[] policyCerts = 
565                signingCertificate.getPolicyInformationCerts(signedData.getCertificates());
566              if (policyCerts != null) {
567                System.out.println("SignedData contains the following certs corresponding to policy informations of SignerInfo No "
568                                   + (signerInfoIndex+1) +":");   
569                for (int j = 0; j < policyCerts.length; j++) {
570                  if (policyCerts[j].getType().equalsIgnoreCase("X.509")) {
571                    System.out.println("X.509 public key cert: " + ((X509Certificate)policyCerts[j]).getSubjectDN());
572                  } else {
573                    System.out.println("X.509 attribute cert: " + ((AttributeCertificate)policyCerts[j]).getHolder());  
574                  }     
575                }  
576              }
577            }  
578          }  
579        
580      }      
581      
582      /**
583       * Creates an attribute certificate just for testing.
584       *
585       * @return the attribute certificate created
586       * @throws CMSException if an error occurs when creating the attribute certificate
587       */
588      public AttributeCertificate createAttributeCertificate() throws CMSException {
589        try {
590            
591          PrivateKey issuerPrivKey = CMSKeyStore.getCaPrivateKey(CMSKeyStore.RSA);
592          X509Certificate issuerCert = CMSKeyStore.getCaCertificate(CMSKeyStore.RSA);
593          Name issuer = (Name)issuerCert.getIssuerDN();
594          GeneralName genName = new GeneralName(GeneralName.directoryName, issuer);
595          GeneralNames genNames = new GeneralNames(genName);
596          V2Form v2Form = new V2Form(genNames);
597          Name subject = (Name)user1Cert_.getSubjectDN();
598          GeneralName genName1 = new GeneralName(GeneralName.directoryName, subject);
599          GeneralNames genNames1 = new GeneralNames(genName1);
600          Holder holder = new Holder();
601          holder.setEntityName(genNames1);
602    
603          AttributeCertificate cert = new AttributeCertificate();
604          cert.setHolder(holder);
605          cert.setIssuer(v2Form);
606          cert.setSerialNumber(new BigInteger("27"));
607          GregorianCalendar c = new GregorianCalendar();
608          Date notBeforeTime = c.getTime();
609          c.add(Calendar.MONTH, 1);
610          Date notAfterTime = c.getTime();
611          cert.setNotBeforeTime(notBeforeTime);
612          cert.setNotAfterTime(notAfterTime);
613          Attribute[] attributes = new Attribute[1];
614          // just for testing some abritrary attribute
615          SEQUENCE postalAddress = new SEQUENCE();
616          postalAddress.addComponent(new UTF8String("A-8010 Graz, Austria"));
617          postalAddress.addComponent(new UTF8String("Inffeldgasse 16A"));
618          attributes[0] = new Attribute(ObjectID.postalAddress, new ASN1Object[] {postalAddress});
619          cert.setAttributes(attributes);
620          cert.sign((AlgorithmID)AlgorithmID.sha256WithRSAEncryption.clone(), issuerPrivKey);
621          cert.verify(issuerCert.getPublicKey());
622          return cert;
623        } catch (Exception ex) {
624          throw new CMSException("Error creating attribute certificate: " + ex.toString());   
625        }    
626      
627      }  
628    
629      /**
630       * Tests the CMS SignedData implementation.
631       */
632      public void start() {
633         // the test message
634        String m = "This is the test message.";
635        System.out.println("Test message: \""+m+"\"");
636        System.out.println();
637        byte[] message = m.getBytes();
638       
639        try {
640          byte[] encoding;
641          byte[] received_message = null;
642          System.out.println("Stream implementation demos");
643          System.out.println("===========================");
644          //
645          // test CMS Implicit SignedDataStream
646          //
647          System.out.println("\nImplicit SignedDataStream demo [create]:\n");
648          encoding = createSignedDataStream(message, SignedDataStream.IMPLICIT);
649          // transmit data
650          System.out.println("\nImplicit SignedDataStream demo [parse]:\n");
651          received_message = getSignedDataStream(encoding, null);
652          System.out.print("\nSigned content: ");
653          System.out.println(new String(received_message));
654          
655          //
656          // test CMS Explicit SignedDataStream
657          //
658          System.out.println("\nExplicit SignedDataStream demo [create]:\n");
659          encoding = createSignedDataStream(message, SignedDataStream.EXPLICIT);
660          // transmit data
661          System.out.println("\nExplicit SignedDataStream demo [parse]:\n");
662          received_message = getSignedDataStream(encoding, message);
663          System.out.print("\nSigned content: ");
664          System.out.println(new String(received_message));
665                
666          // the non-stream implementation
667          System.out.println("\nNon-stream implementation demos");
668          System.out.println("===============================");
669       
670          //
671          // test CMS Implicit SignedData
672          //
673          System.out.println("\nImplicit CMS SignedData demo [create]:\n");
674          encoding = createSignedData(message, SignedData.IMPLICIT);
675          // transmit data
676          System.out.println("\nImplicit CMS SignedData demo [parse]:\n");
677          received_message = getSignedData(encoding, null);
678          System.out.print("\nSigned content: ");
679          System.out.println(new String(received_message));
680    
681          //
682          // test CMS Explicit SignedData
683          //
684          System.out.println("\nExplicit CMS SignedData demo [create]:\n");
685          encoding = createSignedData(message, SignedData.EXPLICIT);
686          // transmit data
687          System.out.println("\nExplicit CMS SignedData demo [parse]:\n");
688          received_message = getSignedData(encoding, message);
689          System.out.print("\nSigned content: ");
690          System.out.println(new String(received_message));
691          
692            } catch (Exception ex) {
693              ex.printStackTrace();
694              throw new RuntimeException(ex.toString());
695            }
696      }
697      
698      /**
699       * The main method.
700       * 
701       * @throws IOException 
702       *            if an I/O error occurs when reading required keys
703       *            and certificates from files
704       */
705      public static void main(String argv[]) throws Exception {
706    
707            DemoUtil.initDemos();
708        (new SignedDataDemo()).start();
709        System.out.println("\nReady!");
710        DemoUtil.waitKey();
711      }
712    }