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/basic/SMimeV3Demo.java 49    12.02.25 17:58 Dbratko $
059    // $Revision: 49 $
060    //
061    
062    package demo.smime.basic;
063    
064    import java.io.ByteArrayInputStream;
065    import java.io.ByteArrayOutputStream;
066    import java.io.IOException;
067    import java.security.NoSuchAlgorithmException;
068    import java.security.PrivateKey;
069    import java.util.Date;
070    
071    import javax.activation.DataHandler;
072    import javax.activation.FileDataSource;
073    import javax.mail.Message;
074    import javax.mail.MessagingException;
075    import javax.mail.Multipart;
076    import javax.mail.Session;
077    import javax.mail.internet.InternetAddress;
078    import javax.mail.internet.MimeBodyPart;
079    import javax.mail.internet.MimeMessage;
080    import javax.mail.internet.MimeMultipart;
081    
082    import demo.DemoSMimeUtil;
083    import demo.DemoUtil;
084    import demo.keystore.CMSKeyStore;
085    import demo.smime.DumpMessage;
086    import iaik.asn1.ObjectID;
087    import iaik.asn1.structures.AlgorithmID;
088    import iaik.asn1.structures.Name;
089    import iaik.cms.CMSAlgorithmID;
090    import iaik.pkcs.PKCSException;
091    import iaik.pkcs.pkcs10.CertificateRequest;
092    import iaik.smime.AuthEncryptedContent;
093    import iaik.smime.CompressedContent;
094    import iaik.smime.EncryptedContent;
095    import iaik.smime.PKCS10Content;
096    import iaik.smime.SMimeBodyPart;
097    import iaik.smime.SMimeException;
098    import iaik.smime.SMimeMultipart;
099    import iaik.smime.SMimeParameters;
100    import iaik.smime.SignedContent;
101    import iaik.x509.X509Certificate;
102    
103    /**
104     * This class demonstrates the usage of the IAIK S/MIME implementation. It shows how to create
105     * signed and/or encrypted S/MIMEv3 messages and how to parse them and verify the signatures 
106     * and decrypt the content, respectively.
107     * <p>
108     * To run this demo the following packages are required:
109     * <ul>
110     *    <li>
111     *       <code>iaik_cms.jar</code> (IAIK-CMS/SMIME)
112     *    </li>
113     *    <li>
114     *       <code>iaik_jce(_full).jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/jca-jce/" target="_blank">IAIK-JCE Core Crypto Library</a>).
115     *    </li>
116     *    <li>
117     *       <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
118     *    </li>   
119     *    <li>
120     *       <code>activation.jar</code> (<a href="http://www.oracle.com/technetwork/java/javase/downloads/index-135046.html" target="_blank">Java Activation Framework</a>; required for JDK versions &lt; 1.6).
121     *    </li> 
122     * </ul>
123     * You also will need the ESDH implementation of IAIK-JCE contained in <code>iaik_esdh.jar</code> or
124     * <code>iaik_jce_full.jar</code>; the first may be used in addition to <code>iaik_jce.jar</code>,
125     * the second instead of <code>iaik_jce.jar</code>.
126     */
127    public class SMimeV3Demo {
128        
129      // whether to print dump all generates test messages to System.out
130      final static boolean PRINT_MESSAGES = false;   
131      
132    
133      String firstName = "John";
134      String lastName = "SMime";
135      String to = "smimetest@iaik.tugraz.at";     // email recipient
136      String from = "smimetest@iaik.tugraz.at";   // email sender
137      String host = "mailhost";                       // name of the mailhost
138    
139      X509Certificate[] signerCertificates;          // list of certificates to include in the S/MIME message
140      X509Certificate recipientCertificate;          // certificate of the recipient
141      X509Certificate signerCertificate;             // certificate of the signer/sender
142      X509Certificate encryptionCertOfSigner;        // signer uses different certificate for encryption
143      PrivateKey signerPrivateKey;                   // private key of the signer/sender
144      
145      /**
146       * Default constructor. Reads certificates and keys from the demo keystore.
147       */
148      public SMimeV3Demo() {
149        
150        System.out.println();
151        System.out.println("********************************************************************************************");
152        System.out.println("*                                SMimeV3Demo demo                                          *");
153        System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIMEv3 messages) *");
154        System.out.println("********************************************************************************************");
155        System.out.println();
156        
157        // get the certificates from the KeyStore
158        signerCertificates = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1);
159        signerPrivateKey = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1);
160        signerCertificate = signerCertificates[0];
161    
162        // recipient = signer for this test
163        recipientCertificate = CMSKeyStore.getCertificateChain(CMSKeyStore.ESDH, CMSKeyStore.SZ_2048_CRYPT_1)[0];
164        if (recipientCertificate == null) {
165          throw new NullPointerException("ESDH certificate not available! Add iaik_esdh.jar to your classpath!");
166        }
167        encryptionCertOfSigner = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
168      }
169      
170      /**
171       * Starts the demo.
172       *
173       * @throws IOException if an I/O related error occurs
174       */
175      public void start() throws IOException {
176    
177        // get the default Session
178            Session session = DemoSMimeUtil.getSession();
179    
180            try {
181          // Create a demo Multipart
182          MimeBodyPart mbp1 = new SMimeBodyPart();
183              mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
184              // attachment
185          MimeBodyPart attachment = new SMimeBodyPart();
186          attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
187          attachment.setFileName("test.html");
188    
189          Multipart mp = new SMimeMultipart();
190          mp.addBodyPart(mbp1);
191          mp.addBodyPart(attachment);
192          DataHandler multipart = new DataHandler(mp, mp.getContentType());
193    
194          Message msg;    // the message to send
195          ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
196          ByteArrayInputStream bais;  // we read from a stream
197    
198          // 1. This is a plain message
199          msg = createPlainMessage(session, multipart);
200          System.out.println("creating plain message...");
201              msg.saveChanges();
202              msg.writeTo(baos);
203              bais = new ByteArrayInputStream(baos.toByteArray());
204              msg = new MimeMessage(session, bais);
205              if (PRINT_MESSAGES) {
206            printMessage(msg);
207          }
208              DumpMessage.dumpMsg(msg);
209              
210              System.out.println("\n\n*****************************************\n\n");
211    
212          // 2. This is an explicitly signed message
213          msg = createSignedMessage(session, multipart, false, AlgorithmID.sha256, AlgorithmID.dsaWithSHA256);
214          System.out.println("creating explicitly signed message...");
215          baos.reset();
216              msg.saveChanges();
217              msg.writeTo(baos);
218              bais = new ByteArrayInputStream(baos.toByteArray());
219              msg = new MimeMessage(session, bais);
220              if (PRINT_MESSAGES) {
221            printMessage(msg);
222          }
223              DumpMessage.dumpMsg(msg);
224              
225              System.out.println("\n\n*****************************************\n\n");
226    
227    
228          // 3. This is an implicitly signed message
229          msg = createSignedMessage(session, multipart, true, AlgorithmID.sha256, AlgorithmID.dsaWithSHA256);
230          System.out.println("creating implicitly signed message...");
231              baos.reset();
232              msg.saveChanges();
233              msg.writeTo(baos);
234              bais = new ByteArrayInputStream(baos.toByteArray());
235              msg = new MimeMessage(session, bais);
236              if (PRINT_MESSAGES) {
237            printMessage(msg);
238          }
239              DumpMessage.dumpMsg(msg);
240              
241              System.out.println("\n\n*****************************************\n\n");
242    
243          // 4. Now create encrypted messages with different content encryption algorithms
244              
245              // RC2 is deprecated; only demonstrated here
246          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 40, 
247            (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(), 128);
248          System.out.println("creating encrypted message [RC2/40]...");
249              baos.reset();
250              msg.saveChanges();
251              msg.writeTo(baos);
252              bais = new ByteArrayInputStream(baos.toByteArray());
253              msg = new MimeMessage(session, bais);
254              if (PRINT_MESSAGES) {
255            printMessage(msg);
256          }
257              DumpMessage.dumpMsg(msg);
258              
259              System.out.println("\n\n*****************************************\n\n");
260              
261              // RC2 is deprecated; only demonstrated here
262          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 64, 
263            (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(), 128);
264          System.out.println("creating encrypted message [RC2/64]...");
265              baos.reset();
266              msg.saveChanges();
267              msg.writeTo(baos);
268              bais = new ByteArrayInputStream(baos.toByteArray());
269              msg = new MimeMessage(session, bais);
270              if (PRINT_MESSAGES) {
271            printMessage(msg);
272          }
273              DumpMessage.dumpMsg(msg);
274              
275              System.out.println("\n\n*****************************************\n\n");
276              
277              // RC2 is deprecated; only demonstrated here
278          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128,
279            (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)AlgorithmID.cms_rc2_wrap.clone(), 128);
280          System.out.println("creating encrypted message [RC2/128]...");
281              baos.reset();
282              msg.saveChanges();
283              msg.writeTo(baos);
284              bais = new ByteArrayInputStream(baos.toByteArray());
285              msg = new MimeMessage(session, bais);
286              if (PRINT_MESSAGES) {
287            printMessage(msg);
288          }
289              DumpMessage.dumpMsg(msg);
290              
291              
292              System.out.println("\n\n*****************************************\n\n");
293              
294              // DES EDE is deprecated; only demonstrated here
295          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 192,
296            (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)AlgorithmID.cms_3DES_wrap.clone(), 192);
297          System.out.println("creating encrypted message [TripleDES]...");
298              baos.reset();
299              msg.saveChanges();
300              msg.writeTo(baos);
301              bais = new ByteArrayInputStream(baos.toByteArray());
302              msg = new MimeMessage(session, bais);
303              if (PRINT_MESSAGES) {
304            printMessage(msg);
305          }
306              DumpMessage.dumpMsg(msg);
307          
308          System.out.println("\n\n*****************************************\n\n");
309          
310          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 128,
311            (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes128_wrap.clone(), 128);
312          System.out.println("creating encrypted message [AES/128]...");
313          baos.reset();
314          msg.saveChanges();
315          msg.writeTo(baos);
316          bais = new ByteArrayInputStream(baos.toByteArray());
317          msg = new MimeMessage(session, bais);
318          if (PRINT_MESSAGES) {
319            printMessage(msg);
320          }
321          DumpMessage.dumpMsg(msg);
322          
323          System.out.println("\n\n*****************************************\n\n");
324          
325          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CBC.clone(), 192,
326            (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes192_wrap.clone(), 192);
327          System.out.println("creating encrypted message [AES/192]...");
328          baos.reset();
329          msg.saveChanges();
330          msg.writeTo(baos);
331          bais = new ByteArrayInputStream(baos.toByteArray());
332          msg = new MimeMessage(session, bais);
333          if (PRINT_MESSAGES) {
334            printMessage(msg);
335          }
336          DumpMessage.dumpMsg(msg);
337            
338          System.out.println("\n\n*****************************************\n\n");
339            
340          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256,
341            (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256);
342          System.out.println("creating encrypted message [AES/256]...");
343          baos.reset();
344          msg.saveChanges();
345          msg.writeTo(baos);
346          bais = new ByteArrayInputStream(baos.toByteArray());
347          msg = new MimeMessage(session, bais);
348          if (PRINT_MESSAGES) {
349            printMessage(msg);
350          }
351          DumpMessage.dumpMsg(msg);  
352           
353          
354          System.out.println("\n\n*****************************************\n\n");
355    
356          // 5. Now create an implicitly signed and encrypted message with attachment
357          msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, true);
358          System.out.println("creating implicitly signed and encrypted message [AES/256]...");
359              baos.reset();
360              msg.saveChanges();
361              msg.writeTo(baos);
362              bais = new ByteArrayInputStream(baos.toByteArray());
363              msg = new MimeMessage(session, bais);
364              if (PRINT_MESSAGES) {
365            printMessage(msg);
366          }
367              DumpMessage.dumpMsg(msg);
368              
369              System.out.println("\n\n*****************************************\n\n");
370    
371          // 6. Now create an explicitly signed and encrypted message with attachment
372          msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, false);
373          System.out.println("creating explicitly signed and encrypted message [AES/256]...");
374              baos.reset();
375              msg.saveChanges();
376              msg.writeTo(baos);
377              bais = new ByteArrayInputStream(baos.toByteArray());
378              msg = new MimeMessage(session, bais);
379              if (PRINT_MESSAGES) {
380            printMessage(msg);
381          }
382              DumpMessage.dumpMsg(msg);
383              
384              System.out.println("\n\n*****************************************\n\n");
385              
386              // 7. Now create authenticated encrypted messages with different content encryption algorithms
387              if (DemoUtil.getIaikProviderVersion() >= 5.62) {
388                
389                msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128,
390                (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes128_wrap.clone(), 128);
391            System.out.println("creating authenticated encrypted message [AES-GCM/128]...");
392            baos.reset();
393            msg.saveChanges();
394            msg.writeTo(baos);
395            bais = new ByteArrayInputStream(baos.toByteArray());
396            msg = new MimeMessage(session, bais);
397            if (PRINT_MESSAGES) {
398              printMessage(msg);
399            }
400            DumpMessage.dumpMsg(msg);  
401             
402            System.out.println("\n\n*****************************************\n\n");
403            
404            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192,
405                (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes192_wrap.clone(), 192);
406            System.out.println("creating authenticated encrypted message [AES-GCM/192]...");
407            baos.reset();
408            msg.saveChanges();
409            msg.writeTo(baos);
410            bais = new ByteArrayInputStream(baos.toByteArray());
411            msg = new MimeMessage(session, bais);
412            if (PRINT_MESSAGES) {
413              printMessage(msg);
414            }
415            DumpMessage.dumpMsg(msg);  
416             
417            System.out.println("\n\n*****************************************\n\n");
418                
419                msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256,
420                    (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256);
421                System.out.println("creating authenticated encrypted message [AES-GCM/256]...");
422                baos.reset();
423                msg.saveChanges();
424                msg.writeTo(baos);
425                bais = new ByteArrayInputStream(baos.toByteArray());
426                msg = new MimeMessage(session, bais);
427                if (PRINT_MESSAGES) {
428                  printMessage(msg);
429                }
430                DumpMessage.dumpMsg(msg);  
431                 
432                System.out.println("\n\n*****************************************\n\n");
433                
434                msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128,
435                (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes128_wrap.clone(), 128);
436            System.out.println("creating authenticated encrypted message [AES-CCM/128]...");
437            baos.reset();
438            msg.saveChanges();
439            msg.writeTo(baos);
440            bais = new ByteArrayInputStream(baos.toByteArray());
441            msg = new MimeMessage(session, bais);
442            if (PRINT_MESSAGES) {
443              printMessage(msg);
444            }
445            DumpMessage.dumpMsg(msg);  
446             
447            System.out.println("\n\n*****************************************\n\n");
448            
449            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192,
450                (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes192_wrap.clone(), 192);
451            System.out.println("creating authenticated encrypted message [AES-CCM/192]...");
452            baos.reset();
453            msg.saveChanges();
454            msg.writeTo(baos);
455            bais = new ByteArrayInputStream(baos.toByteArray());
456            msg = new MimeMessage(session, bais);
457            if (PRINT_MESSAGES) {
458              printMessage(msg);
459            }
460            DumpMessage.dumpMsg(msg);  
461            
462            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256,
463                (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256);
464            System.out.println("creating authenticated encrypted message [AES-CCM/256]...");
465            baos.reset();
466            msg.saveChanges();
467            msg.writeTo(baos);
468            bais = new ByteArrayInputStream(baos.toByteArray());
469            msg = new MimeMessage(session, bais);
470            if (PRINT_MESSAGES) {
471              printMessage(msg);
472            }
473            DumpMessage.dumpMsg(msg);  
474             
475            System.out.println("\n\n*****************************************\n\n");
476            
477            msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256,
478                (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone(), (AlgorithmID)CMSAlgorithmID.cms_aes256_wrap.clone(), 256);
479            System.out.println("creating authenticated encrypted message [ChaChaPoly1305]...");
480            baos.reset();
481            msg.saveChanges();
482            msg.writeTo(baos);
483            bais = new ByteArrayInputStream(baos.toByteArray());
484            msg = new MimeMessage(session, bais);
485            if (PRINT_MESSAGES) {
486              printMessage(msg);
487            }
488            DumpMessage.dumpMsg(msg);  
489             
490            System.out.println("\n\n*****************************************\n\n");
491                
492            // Create an implicitly signed and authenticated encrypted message with attachment
493            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), multipart, true);
494            System.out.println("creating implicitly signed and encrypted message [AES-GCM/256]...");
495            baos.reset();
496            msg.saveChanges();
497            msg.writeTo(baos);
498            bais = new ByteArrayInputStream(baos.toByteArray());
499            msg = new MimeMessage(session, bais);
500            if (PRINT_MESSAGES) {
501              printMessage(msg);
502            }
503            DumpMessage.dumpMsg(msg);
504            
505            System.out.println("\n\n*****************************************\n\n");
506    
507            // Create an explicitly signed and encrypted message with attachment
508            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), multipart, false);
509            System.out.println("creating explicitly signed and encrypted message [AES-GCM/256]...");
510            baos.reset();
511            msg.saveChanges();
512            msg.writeTo(baos);
513            bais = new ByteArrayInputStream(baos.toByteArray());
514            msg = new MimeMessage(session, bais);
515            if (PRINT_MESSAGES) {
516              printMessage(msg);
517            }
518            DumpMessage.dumpMsg(msg);
519            
520            System.out.println("\n\n*****************************************\n\n");
521            
522            // Create an implicitly signed and authenticated encrypted message with attachment
523            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), multipart, true);
524            System.out.println("creating implicitly signed and encrypted message [AES-CCM/256]...");
525            baos.reset();
526            msg.saveChanges();
527            msg.writeTo(baos);
528            bais = new ByteArrayInputStream(baos.toByteArray());
529            msg = new MimeMessage(session, bais);
530            if (PRINT_MESSAGES) {
531              printMessage(msg);
532            }
533            DumpMessage.dumpMsg(msg);
534            
535            System.out.println("\n\n*****************************************\n\n");
536    
537            // Create an explicitly signed and encrypted message with attachment
538            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), multipart, false);
539            System.out.println("creating explicitly signed and encrypted message [AES-CCM/256]...");
540            baos.reset();
541            msg.saveChanges();
542            msg.writeTo(baos);
543            bais = new ByteArrayInputStream(baos.toByteArray());
544            msg = new MimeMessage(session, bais);
545            if (PRINT_MESSAGES) {
546              printMessage(msg);
547            }
548            DumpMessage.dumpMsg(msg);
549            
550            System.out.println("\n\n*****************************************\n\n");
551            
552            // Create an implicitly signed and authenticated encrypted message with attachment
553            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), multipart, true);
554            System.out.println("creating implicitly signed and encrypted message [ChaCha20Poly1305]...");
555            baos.reset();
556            msg.saveChanges();
557            msg.writeTo(baos);
558            bais = new ByteArrayInputStream(baos.toByteArray());
559            msg = new MimeMessage(session, bais);
560            if (PRINT_MESSAGES) {
561              printMessage(msg);
562            }
563            DumpMessage.dumpMsg(msg);
564            
565            System.out.println("\n\n*****************************************\n\n");
566    
567            // Create an explicitly signed and encrypted message with attachment
568            msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), multipart, false);
569            System.out.println("creating explicitly signed and encrypted message [ChaCha20Poly1305]...");
570            baos.reset();
571            msg.saveChanges();
572            msg.writeTo(baos);
573            bais = new ByteArrayInputStream(baos.toByteArray());
574            msg = new MimeMessage(session, bais);
575            if (PRINT_MESSAGES) {
576              printMessage(msg);
577            }
578            DumpMessage.dumpMsg(msg);
579            
580            System.out.println("\n\n*****************************************\n\n");
581                
582              }
583             
584              // 8. certs only message
585              msg = createCertsOnlyMessage(session);
586              System.out.println("creating certs-only message");
587              baos.reset();
588              msg.saveChanges();
589              msg.writeTo(baos);
590              bais = new ByteArrayInputStream(baos.toByteArray());
591              msg = new MimeMessage(session, bais);
592              if (PRINT_MESSAGES) {
593            printMessage(msg);
594          }
595              DumpMessage.dumpMsg(msg);
596              
597              System.out.println("\n\n*****************************************\n\n");
598    
599              // 9. second certs only message
600              msg = createCertsOnlyMultiPartMessage(session);
601              System.out.println("creating message with certs-only part");
602              baos.reset();
603              msg.saveChanges();
604              msg.writeTo(baos);
605              bais = new ByteArrayInputStream(baos.toByteArray());
606              msg = new MimeMessage(session, bais);
607              if (PRINT_MESSAGES) {
608            printMessage(msg);
609          }
610              DumpMessage.dumpMsg(msg);
611              
612              System.out.println("\n\n*****************************************\n\n");
613    
614              // 10. application/pkcs10 cert request message
615          msg = createPKCS10Message(session);
616          System.out.println("creating application/pkcs10 message...");
617              baos.reset();
618              msg.saveChanges();
619              msg.writeTo(baos);
620              bais = new ByteArrayInputStream(baos.toByteArray());
621              msg = new MimeMessage(session, bais);
622              if (PRINT_MESSAGES) {
623            printMessage(msg);
624          }
625              DumpMessage.dumpMsg(msg);
626              
627              System.out.println("\n\n*****************************************\n\n");
628    
629              // 11. ending application/pkcs10 message where the request is in the second part
630              msg = createPKCS10MultiPartMessage(session);
631              System.out.println("creating message with pkcs10 part...");
632              baos.reset();
633              msg.saveChanges();
634              msg.writeTo(baos);
635              bais = new ByteArrayInputStream(baos.toByteArray());
636              msg = new MimeMessage(session, bais);
637              if (PRINT_MESSAGES) {
638            printMessage(msg);
639          }
640              DumpMessage.dumpMsg(msg);
641              
642              System.out.println("\n\n*****************************************\n\n");
643    
644              // 12. compressed message 
645              msg = createCompressedMessage(session, multipart, (AlgorithmID)CMSAlgorithmID.zlib_compress.clone());
646              System.out.println("creating message with compressed data...");
647              baos.reset();
648              msg.saveChanges();
649              msg.writeTo(baos);
650              bais = new ByteArrayInputStream(baos.toByteArray());
651              msg = new MimeMessage(session, bais);
652              if (PRINT_MESSAGES) {
653            printMessage(msg);
654          }
655              DumpMessage.dumpMsg(msg);
656    
657            } catch (Exception ex) {
658                ex.printStackTrace();
659                throw new RuntimeException(ex.toString());
660            }
661      }
662    
663      /**
664       * Creates a MIME message container with the given subject for the given session.
665       * 
666       * @param session the mail sesion
667       * @param subject the subject of the message
668       *
669       * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
670       *
671       * @throws MessagingException if the message cannot be created
672       */
673      public Message createMessage(Session session, String subject) throws MessagingException {
674        MimeMessage msg = new MimeMessage(session);
675        msg.setFrom(new InternetAddress(from));
676            msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to, false));
677            msg.setSentDate(new Date());
678        msg.setSubject(subject);
679        return msg;
680      }
681      
682      /**
683       * Creates a simple plain (neither signed nor encrypted) message.
684       *
685       * @param session the mail session
686       * @param dataHandler the content of the message
687       * 
688       * @return the plain message
689       *
690       * @throws MessagingException if an error occurs when creating the message
691       */
692      public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException {
693    
694        Message msg = createMessage(session, "IAIK-S/MIME: Plain message");
695        if (dataHandler != null) {
696          msg.setDataHandler(dataHandler);
697        } else {
698          msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n");
699        }
700        return msg;
701      }
702      
703      /**
704       * Creates a signed and encrypted message.
705       *
706       * @param session the mail session
707       * @param algorithm the content encryption algorithm to be used
708       * @param dataHandler the content of the message to be signed and encrypted
709       * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
710       *                 (multipart/signed) signing
711       * 
712       * @return the signed and encrypted message
713       *
714       * @throws MessagingException if an error occurs when creating the message
715       */
716      public Message createSignedAndEncryptedMessage(Session session, AlgorithmID algorithm, DataHandler dataHandler, boolean implicit)
717        throws MessagingException {
718    
719        String subject = null;
720        String text = null;
721        if (implicit) {
722          subject = "IAIK-S/MIME: Implicitly Signed and Encrypted";
723          text = "This message is implicitly signed and encrypted!\n\n\n";
724        } else {
725          subject = "IAIK-S/MIME: Explicitly Signed and Encrypted";
726          text = "This message is explicitly signed and encrypted!\n\n\n";
727        }
728        Message msg = createMessage(session, subject);
729    
730        SignedContent sc = new SignedContent(implicit);
731        if (dataHandler != null) {
732          sc.setDataHandler(dataHandler);
733        } else {
734          sc.setText(text);
735        }
736        sc.setCertificates(signerCertificates);
737        try {
738          sc.addSigner(signerPrivateKey, 
739                       signerCertificate,
740                       (AlgorithmID)AlgorithmID.sha256.clone(),
741                       (AlgorithmID)AlgorithmID.dsaWithSHA256.clone());
742        } catch (NoSuchAlgorithmException ex) {
743          throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
744        }
745    
746        EncryptedContent ec = null;
747        if (algorithm.equals(AlgorithmID.aes256_CBC)) {
748          ec = new EncryptedContent(sc);
749        } else {
750          ec = new AuthEncryptedContent(sc);
751        }
752        // encrypt for the recipient
753        AlgorithmID keyEA = (AlgorithmID)AlgorithmID.esdhKeyAgreement.clone();
754        // the key wrap algorithm to use:
755        AlgorithmID keyWrapAlg = (AlgorithmID)AlgorithmID.cms_aes256_wrap.clone();
756        // the length of the key encryption key to be generated:
757        int kekLength = 256;
758        try {  
759          ec.addRecipient(recipientCertificate, keyEA, keyWrapAlg, kekLength);
760        } catch (SMimeException ex) {
761          throw new MessagingException("Error adding ESDH recipient: " + ex.getMessage());   
762        }    
763        // I want to be able to decrypt the message, too
764        ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
765        // set the encryption algorithm
766        try {
767          ec.setEncryptionAlgorithm(algorithm, -1);
768        } catch (NoSuchAlgorithmException ex) {
769          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
770        }   
771        msg.setContent(ec, ec.getContentType());
772        // let the EncryptedContent update some message headers
773        ec.setHeaders(msg);
774    
775        return msg;
776      }
777      
778      /**
779       * Creates a signed message.
780       *
781       * @param session the mail session
782       * @param dataHandler the content of the message to be signed
783       * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
784       *                 (multipart/signed) signing
785       * @param digestAlgorithm the digest algorithm to be used
786       * @param signatureAlgorithm the signature algorithm to be used                
787       * 
788       * @return the signed message
789       *
790       * @throws MessagingException if an error occurs when creating the message
791       */
792      public Message createSignedMessage(Session session, 
793                                         DataHandler dataHandler,
794                                         boolean implicit,
795                                         AlgorithmID digestAlgorithm,
796                                         AlgorithmID signatureAlgorithm)
797          throws MessagingException {
798    
799        String subject = null;
800        StringBuffer buf = new StringBuffer();
801        
802        if (implicit) {
803          subject = "IAIK-S/MIME: Implicitly Signed";
804          buf.append("This message is implicitly signed!\n");
805          buf.append("You need an S/MIME aware mail client to view this message.\n");
806          buf.append("\n\n");
807        } else {
808          subject = "IAIK-S/MIME: Explicitly Signed";
809          buf.append("This message is explicitly signed!\n");
810          buf.append("Every mail client can view this message.\n");
811          buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
812          buf.append("\n\n");
813        }
814        
815        Message msg = createMessage(session, subject);
816        
817        SignedContent sc = new SignedContent(implicit);
818        if (dataHandler != null) {
819          sc.setDataHandler(dataHandler);
820        } else {
821          sc.setText(buf.toString());
822        }
823        sc.setCertificates(signerCertificates);
824    
825        try {
826          sc.addSigner(signerPrivateKey, 
827                       signerCertificate,
828                       (AlgorithmID)digestAlgorithm.clone(),
829                       (AlgorithmID)signatureAlgorithm.clone());
830        } catch (NoSuchAlgorithmException ex) {
831          throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
832        }
833    
834        msg.setContent(sc, sc.getContentType());
835        // let the SignedContent update some message headers
836        sc.setHeaders(msg);
837        return msg;
838      }
839      
840      /**
841       * Creates an encrypted message.
842       *
843       * @param session the mail session
844       * @param contentEA the content encryption algorithm to be used
845       * @param keyLength the length of the secret content encryption key to be created and used
846       * @param keyEA the key encryption algorithm to be used
847       * @param keyWrapAlgorithm the key wrap algorithm to be used
848       * @param kekLength the length of the key encryption algorithm
849       * 
850       * @return the encrypted message
851       *
852       * @throws MessagingException if an error occurs when creating the message
853       */
854      public Message createEncryptedMessage(Session session, AlgorithmID contentEA, int keyLength,
855        AlgorithmID keyEA, AlgorithmID keyWrapAlgorithm, int kekLength)
856          throws MessagingException {
857        
858        AlgorithmID algorithm = (AlgorithmID)contentEA.clone();
859        AlgorithmID keyAgreeAlg = (AlgorithmID)keyEA.clone();
860        AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlgorithm.clone();
861        
862        StringBuffer subject = new StringBuffer();
863        subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName());
864        if (keyLength > 0) {
865          subject.append("/"+keyLength);
866        }  
867        subject.append("]");
868        Message msg = createMessage(session, subject.toString());
869    
870        EncryptedContent ec = new EncryptedContent();
871    
872        StringBuffer buf = new StringBuffer();
873        buf.append("This is the encrypted content!\n");
874        buf.append("Content encryption algorithm: "+algorithm.getName());
875        buf.append("\n\n");
876    
877        ec.setText(buf.toString());
878        
879        try {  
880          ec.addRecipient(recipientCertificate, keyAgreeAlg, keyWrapAlg, kekLength);
881        } catch (SMimeException ex) {
882          throw new MessagingException("Error adding ESDH recipient: " + ex.getMessage());   
883        }    
884        // I want to be able to decrypt the message, too
885        ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
886        try {
887          ec.setEncryptionAlgorithm(algorithm, keyLength);
888        } catch (NoSuchAlgorithmException ex) {
889          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
890        }    
891    
892        msg.setContent(ec, ec.getContentType());
893        // let the EncryptedContent update some message headers
894        ec.setHeaders(msg);
895    
896        return msg;
897      }
898      
899      /**
900       * Creates an authenticated encrypted message.
901       *
902       * @param session the mail session
903       * @param contentEA the content encryption algorithm to be used
904       * @param keyLength the length of the secret content encryption key to be created and used
905       * @param keyEA the key encryption algorithm to be used
906       * @param keyWrapAlgorithm the key wrap algorithm to be used
907       * @param kekLength the length of the key encryption algorithm 
908       * @return the encrypted message
909       *
910       * @throws MessagingException if an error occurs when creating the message
911       */
912      public Message createAuthEncryptedMessage(Session session, AlgorithmID contentEA, int keyLength,
913        AlgorithmID keyEA, AlgorithmID keyWrapAlgorithm, int kekLength)
914          throws MessagingException {
915        
916        AlgorithmID algorithm = (AlgorithmID)contentEA.clone();
917        AlgorithmID keyAgreeAlg = (AlgorithmID)keyEA.clone();
918        AlgorithmID keyWrapAlg = (AlgorithmID)keyWrapAlgorithm.clone();
919        
920        StringBuffer subject = new StringBuffer();
921        subject.append("IAIK-S/MIME: Authenticated Encrypted ["+algorithm.getName());
922        if (keyLength > 0) {
923          subject.append("/"+keyLength);
924        }  
925        subject.append("]");
926        Message msg = createMessage(session, subject.toString());
927    
928        AuthEncryptedContent ec = new AuthEncryptedContent();
929    
930        StringBuffer buf = new StringBuffer();
931        buf.append("This is the authenticated encrypted content!\n");
932        buf.append("Content encryption algorithm: "+algorithm.getName());
933        buf.append("\n\n");
934    
935        ec.setText(buf.toString());
936        
937        try {  
938          ec.addRecipient(recipientCertificate, keyAgreeAlg, keyWrapAlg, kekLength);
939        } catch (SMimeException ex) {
940          throw new MessagingException("Error adding ESDH recipient: " + ex.getMessage());   
941        }    
942        // I want to be able to decrypt the message, too
943        ec.addRecipient(encryptionCertOfSigner, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
944        try {
945          ec.setEncryptionAlgorithm(algorithm, keyLength);
946        } catch (NoSuchAlgorithmException ex) {
947          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
948        }    
949    
950        msg.setContent(ec, ec.getContentType());
951        // let the EncryptedContent update some message headers
952        ec.setHeaders(msg);
953    
954        return msg;
955      }
956      
957      /**
958       * Creates a certs-only message.
959       *
960       * @param session the mail session
961       * 
962       * @return the certs-only message
963       *
964       * @throws MessagingException if an error occurs when creating the message
965       */
966      public Message createCertsOnlyMessage(Session session)
967          throws MessagingException {
968    
969        Message msg = createMessage(session, "IAIK S/MIME: Certs-only message");
970        //use new content types
971        SMimeParameters.useNewContentTypes(true);
972        SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
973        sc.setCertificates(signerCertificates);
974        msg.setContent(sc, sc.getContentType());
975        //set filename and attachment parameters
976        sc.setHeaders(msg);
977    
978        return msg;
979      }
980      
981      
982      /**
983       * Creates a certs-only message where the certificate list is transferred as attachment.
984       *
985       * @param session the mail session
986       * 
987       * @return the certs-only message
988       *
989       * @throws MessagingException if an error occurs when creating the message
990       */
991      public Message createCertsOnlyMultiPartMessage(Session session) throws MessagingException {
992    
993        MimeBodyPart mbp1 = new MimeBodyPart();
994            mbp1.setText("This is a test where the certs-only message is included in the second part!\n\n");
995    
996        MimeBodyPart attachment = new MimeBodyPart();
997        //use new content types
998        SMimeParameters.useNewContentTypes(true);
999        SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
1000        sc.setCertificates(signerCertificates);
1001        attachment.setContent(sc, sc.getContentType());
1002        // let the SignedContent update some headers
1003        sc.setHeaders(attachment);
1004        Multipart mp = new MimeMultipart();
1005        mp.addBodyPart(mbp1);
1006        mp.addBodyPart(attachment);
1007    
1008        Message msg = createMessage(session, "IAIK S/MIME: Certs-only multipart message");
1009        msg.setContent(mp, mp.getContentType());
1010        return msg;
1011      }
1012      
1013       /**
1014       * Creates a compressed message.
1015       *
1016       * @param session the mail session
1017       * @param dataHandler the datahandler supplying the content to be compressed
1018       * @param algorithm the compression algorithm to be used
1019       * 
1020       * @return the compressed message
1021       *
1022       * @throws MessagingException if an error occurs when creating the message
1023       */
1024      public Message createCompressedMessage(Session session, DataHandler dataHandler, AlgorithmID algorithm)
1025          throws MessagingException {
1026    
1027        String subject = "IAIK-S/MIME: Compressed ["+algorithm.getName()+"]";
1028        Message msg = createMessage(session, subject.toString());
1029    
1030        CompressedContent compressedContent = new CompressedContent();
1031        
1032        if (dataHandler == null) {
1033          StringBuffer buf = new StringBuffer();
1034          buf.append("This is the compressed content!\n");
1035          buf.append("Compression algorithm: "+algorithm.getName());
1036          buf.append("\n\n");
1037          compressedContent.setText(buf.toString());
1038        } else {
1039          compressedContent.setDataHandler(dataHandler);   
1040        }    
1041        
1042        try {
1043          compressedContent.setCompressionAlgorithm(algorithm);
1044        } catch (NoSuchAlgorithmException ex) {
1045          throw new MessagingException("Compression algorithm not supported: " + ex.getMessage());   
1046        }   
1047    
1048        msg.setContent(compressedContent, compressedContent.getContentType());
1049        // let the CompressedContent update some message headers
1050        compressedContent.setHeaders(msg);
1051    
1052        return msg;
1053      }
1054    
1055      /**
1056       * Creates a PKCS#10 certificate request message.
1057       *
1058       * @param session the mail session
1059       * 
1060       * @return the PKCS#10 certificate request message
1061       *
1062       * @throws MessagingException if an error occurs when creating the message
1063       */
1064      public Message createPKCS10Message(Session session)
1065        throws MessagingException {
1066    
1067        Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request");
1068    
1069        PKCS10Content pc = new PKCS10Content();
1070        CertificateRequest request = null;
1071        try {
1072           request = createCertificateRequest();
1073        } catch (PKCSException ex) {
1074           throw new MessagingException(ex.getMessage());
1075        }
1076        pc.setCertRequest(request);
1077        msg.setContent(pc, pc.getContentType());
1078        // let the PKCS10Content update some message headers
1079        pc.setHeaders(msg);
1080    
1081        return msg;
1082      }
1083    
1084    
1085      private CertificateRequest createCertificateRequest() throws PKCSException {
1086        try {
1087          Name subject = new Name();
1088              subject.addRDN(ObjectID.commonName, firstName + " " + lastName);
1089              subject.addRDN(ObjectID.emailAddress, from);
1090              CertificateRequest certRequest;
1091          certRequest = new CertificateRequest(signerCertificate.getPublicKey(), subject);
1092              certRequest.sign((AlgorithmID)AlgorithmID.dsaWithSHA256.clone(), signerPrivateKey);
1093              certRequest.verify();
1094              return certRequest;
1095            } catch (Exception ex) {
1096              throw new PKCSException("Cannot create cert request: " + ex.getMessage());
1097            }
1098    
1099      }
1100      
1101      /**
1102       * Creates a PKCS#10 message where the certificate request is transferred as attachment.
1103       *
1104       * @param session the mail session
1105       * 
1106       * @return the PKCS#10 certificate request message
1107       *
1108       * @throws MessagingException if an error occurs when creating the message
1109       */
1110      public Message createPKCS10MultiPartMessage(Session session) throws MessagingException {
1111    
1112        MimeBodyPart mbp1 = new MimeBodyPart();
1113            mbp1.setText("This is a test where the request message is included in the second part!\n\n");
1114            // try to test an attachment
1115            // this demo attaches our homepage
1116        MimeBodyPart attachment = new MimeBodyPart();
1117        //use new content types
1118        SMimeParameters.useNewContentTypes(true);
1119        PKCS10Content pc = new PKCS10Content();
1120        CertificateRequest request = null;
1121        try {
1122          request = createCertificateRequest();
1123        } catch (PKCSException ex) {
1124          throw new MessagingException(ex.getMessage());
1125        }
1126        pc.setCertRequest(request);
1127        DataHandler pkcs10Handler = new DataHandler(pc, pc.getContentType());
1128        attachment.setDataHandler(pkcs10Handler);
1129        attachment.setDisposition("attachment");
1130        attachment.setFileName("smime.p10");
1131        Multipart mp = new MimeMultipart();
1132        mp.addBodyPart(mbp1);
1133        mp.addBodyPart(attachment);
1134    
1135        Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request multipart message");
1136        msg.setContent(mp, mp.getContentType());
1137        return msg;
1138      }
1139      
1140      /** 
1141       * Prints a dump of the given message to System.out.
1142       *
1143       * @param msg the message to be dumped to System.out
1144       *
1145       * @throws IOException if an I/O error occurs
1146       */
1147      static void printMessage(Message msg) throws IOException {
1148        System.out.println("------------------------------------------------------------------");
1149        System.out.println("Message dump: \n");
1150        try {
1151          msg.writeTo(System.out);
1152        } catch (MessagingException ex) {
1153          throw new IOException(ex.getMessage());   
1154        }    
1155        System.out.println("\n------------------------------------------------------------------");
1156      }  
1157    
1158    
1159      /**
1160       * The main method.
1161       */
1162      public static void main(String[] argv) throws IOException {
1163         
1164        DemoSMimeUtil.initDemos();
1165            (new SMimeV3Demo()).start();
1166        System.out.println("\nReady!");
1167        DemoUtil.waitKey();
1168      }
1169    }