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