001// Copyright (C) 2002 IAIK
002// https://sic.tech/
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// This source is provided for inspection purposes and recompilation only,
011// unless specified differently in a contract with IAIK. This source has to
012// be kept in strict confidence and must not be disclosed to any third party
013// under any circumstances. Redistribution in source and binary forms, with
014// or without modification, are <not> permitted in any case!
015//
016// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
017// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
018// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
019// ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
020// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
021// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
022// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
023// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
024// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
025// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
026// SUCH DAMAGE.
027//
028// $Header: /IAIK-CMS/current/src/demo/smime/basic/SMimeDemo.java 53    12.02.25 17:58 Dbratko $
029// $Revision: 53 $
030//
031
032package demo.smime.basic;
033
034import java.io.ByteArrayInputStream;
035import java.io.ByteArrayOutputStream;
036import java.io.IOException;
037import java.security.NoSuchAlgorithmException;
038import java.security.PrivateKey;
039import java.security.interfaces.RSAPrivateKey;
040import java.util.Date;
041
042import jakarta.activation.DataHandler;
043import jakarta.activation.FileDataSource;
044import jakarta.mail.Message;
045import jakarta.mail.MessagingException;
046import jakarta.mail.Multipart;
047import jakarta.mail.Session;
048import jakarta.mail.internet.InternetAddress;
049import jakarta.mail.internet.MimeBodyPart;
050import jakarta.mail.internet.MimeMessage;
051import jakarta.mail.internet.MimeMultipart;
052
053import demo.DemoSMimeUtil;
054import demo.DemoUtil;
055import demo.keystore.CMSKeyStore;
056import demo.smime.DumpMessage;
057import iaik.asn1.ObjectID;
058import iaik.asn1.structures.AlgorithmID;
059import iaik.asn1.structures.Name;
060import iaik.cms.CMSAlgorithmID;
061import iaik.pkcs.PKCSException;
062import iaik.pkcs.pkcs10.CertificateRequest;
063import iaik.smime.AuthEncryptedContent;
064import iaik.smime.CompressedContent;
065import iaik.smime.EncryptedContent;
066import iaik.smime.PKCS10Content;
067import iaik.smime.SMimeBodyPart;
068import iaik.smime.SMimeMultipart;
069import iaik.smime.SMimeParameters;
070import iaik.smime.SignedContent;
071import iaik.x509.X509Certificate;
072
073/**
074 * This class demonstrates the usage of the IAIK S/MIME implementation. It shows how to create
075 * signed and/or encrypted S/MIME messages and how to parse them and verify the signatures 
076 * and decrypt the content, respectively.
077 * <p>
078 * To run this demo the following packages are required:
079 * <ul>
080 *    <li>
081 *       <code>iaik_cms.jar</code>
082 *    </li>
083 *    <li>
084 *       <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>).
085 *    </li>
086 *    <li>
087 *       <a href="https://jakarta.ee/specifications/mail/" target="_blank">Jakarta</a>/<a href="https://eclipse-ee4j.github.io/angus-mail/" target="_blank">Angus</a> Mail
088 *    </li>   
089 *    <li>
090 *       <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a>
091 *    </li> 
092 * </ul>
093 */
094public class SMimeDemo {
095    
096  // whether to print dump all generates test messages to System.out
097  final static boolean PRINT_MESSAGES = false;   
098
099  String firstName_ = "John";                     // name of sender
100  String lastName_ = "SMime";
101  String from_ = "smimetest@iaik.tugraz.at";      // email sender
102  String to_ = "smimetest@iaik.tugraz.at";        // email recipient
103  String host_ = "mailhost";                      // name of the mailhost
104
105  X509Certificate[] signerCertificates_;          // list of certificates to include in the S/MIME message
106  X509Certificate recipientCertificate_;          // certificate of the recipient
107  X509Certificate signerCertificate_;             // certificate of the signer/sender
108  X509Certificate encryptionCertOfSigner_;        // signer uses different certificate for encryption
109  PrivateKey signerPrivateKey_;                   // private key of the signer/sender
110  
111  /**
112   * Default constructor. Reads certificates and keys from the demo keystore.
113   */
114  public SMimeDemo() {
115    
116    System.out.println();
117    System.out.println("******************************************************************************************");
118    System.out.println("*                                 SMimeDemo demo                                         *");
119    System.out.println("* (shows how to create and parse (verify, decrypt) signed and encrypted S/MIME messages) *");
120    System.out.println("******************************************************************************************");
121    System.out.println();
122    
123    // get the certificates from the KeyStore
124    signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
125    signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
126    signerCertificate_ = signerCertificates_[0];
127
128    // recipient = signer for this test
129    recipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
130    encryptionCertOfSigner_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
131  }
132  
133  /**
134   * Starts the demo.
135   *
136   * @throws IOException if an I/O related error occurs
137   */
138  public void start() throws IOException {
139
140        // get the default Session
141        Session session = DemoSMimeUtil.getSession();
142
143        try {
144      // Create a demo Multipart
145      MimeBodyPart mbp1 = new SMimeBodyPart();
146      mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
147          // attachment
148      MimeBodyPart attachment = new SMimeBodyPart();
149      attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
150      attachment.setFileName("test.html");
151        
152      Multipart mp = new SMimeMultipart();
153      mp.addBodyPart(mbp1);
154      mp.addBodyPart(attachment);
155      DataHandler multipart = new DataHandler(mp, mp.getContentType());
156
157      Message msg;    // the message to send
158      ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
159      ByteArrayInputStream bais;  // we read from a stream
160
161      // 1. This is a plain message
162      msg = createPlainMessage(session, multipart);
163      System.out.println("creating plain message...");
164          msg.saveChanges();
165          msg.writeTo(baos);
166          bais = new ByteArrayInputStream(baos.toByteArray());
167          msg = new MimeMessage(session, bais);
168          if (PRINT_MESSAGES) {
169        printMessage(msg);
170      }
171          DumpMessage.dumpMsg(msg);
172          
173          System.out.println("\n\n*****************************************\n\n");
174
175      // 2. This is an explicitly signed message
176      msg = createSignedMessage(session, multipart, false);
177      System.out.println("creating explicitly signed message...");
178      baos.reset();
179          msg.saveChanges();
180          msg.writeTo(baos);
181          bais = new ByteArrayInputStream(baos.toByteArray());
182          msg = new MimeMessage(session, bais);
183          if (PRINT_MESSAGES) {
184        printMessage(msg);
185      }
186          DumpMessage.dumpMsg(msg);
187          
188          System.out.println("\n\n*****************************************\n\n");
189
190
191      // 3. This is an implicitly signed message
192      msg = createSignedMessage(session, multipart, true);
193      System.out.println("creating implicitly signed message...");
194          baos.reset();
195          msg.saveChanges();
196          msg.writeTo(baos);
197          bais = new ByteArrayInputStream(baos.toByteArray());
198          msg = new MimeMessage(session, bais);
199          if (PRINT_MESSAGES) {
200        printMessage(msg);
201      }
202          DumpMessage.dumpMsg(msg);
203          
204          System.out.println("\n\n*****************************************\n\n");
205
206      // 4. Now create encrypted messages with different content encryption algorithms
207          
208      // RC2 is deprecated; only demonstrated here
209      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 40);
210      System.out.println("creating encrypted message [RC2/40]...");
211          baos.reset();
212          msg.saveChanges();
213          msg.writeTo(baos);
214          bais = new ByteArrayInputStream(baos.toByteArray());
215          msg = new MimeMessage(session, bais);
216          if (PRINT_MESSAGES) {
217        printMessage(msg);
218      }
219          DumpMessage.dumpMsg(msg);
220          
221          System.out.println("\n\n*****************************************\n\n");
222          
223          // RC2 is deprecated; only demonstrated here
224      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 64);
225      System.out.println("creating encrypted message [RC2/64]...");
226          baos.reset();
227          msg.saveChanges();
228          msg.writeTo(baos);
229          bais = new ByteArrayInputStream(baos.toByteArray());
230          msg = new MimeMessage(session, bais);
231          if (PRINT_MESSAGES) {
232        printMessage(msg);
233      }
234          DumpMessage.dumpMsg(msg);
235          
236          System.out.println("\n\n*****************************************\n\n");
237          
238          // RC2 is deprecated; only demonstrated here
239      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128);
240      System.out.println("creating encrypted message [RC2/128]...");
241          baos.reset();
242          msg.saveChanges();
243          msg.writeTo(baos);
244          bais = new ByteArrayInputStream(baos.toByteArray());
245          msg = new MimeMessage(session, bais);
246          if (PRINT_MESSAGES) {
247        printMessage(msg);
248      }
249          DumpMessage.dumpMsg(msg);
250          
251          System.out.println("\n\n*****************************************\n\n");
252          
253          // DES EDE is deprecated; only demonstrated here
254      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 192);
255      System.out.println("creating encrypted message [TripleDES]...");
256          baos.reset();
257          msg.saveChanges();
258          msg.writeTo(baos);
259          bais = new ByteArrayInputStream(baos.toByteArray());
260          msg = new MimeMessage(session, bais);
261          if (PRINT_MESSAGES) {
262        printMessage(msg);
263      }
264          DumpMessage.dumpMsg(msg);
265          
266          System.out.println("\n\n*****************************************\n\n");
267      
268      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 128);
269      System.out.println("creating encrypted message [AES/128]...");
270      baos.reset();
271      msg.saveChanges();
272      msg.writeTo(baos);
273      bais = new ByteArrayInputStream(baos.toByteArray());
274      msg = new MimeMessage(session, bais);
275      if (PRINT_MESSAGES) {
276        printMessage(msg);
277      }
278      DumpMessage.dumpMsg(msg);
279      
280      System.out.println("\n\n*****************************************\n\n");
281      
282      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CBC.clone(), 192);
283      System.out.println("creating encrypted message [AES/192]...");
284      baos.reset();
285      msg.saveChanges();
286      msg.writeTo(baos);
287      bais = new ByteArrayInputStream(baos.toByteArray());
288      msg = new MimeMessage(session, bais);
289      if (PRINT_MESSAGES) {
290        printMessage(msg);
291      }
292      DumpMessage.dumpMsg(msg);
293      
294      System.out.println("\n\n*****************************************\n\n");
295      
296      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256);
297      System.out.println("creating encrypted message [AES/256]...");
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
311      // 5. Now create a implicitly signed and encrypted message with attachment
312      msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, true);
313      System.out.println("creating implicitly signed and encrypted message [AES/256]...");
314          baos.reset();
315          msg.saveChanges();
316          msg.writeTo(baos);
317          bais = new ByteArrayInputStream(baos.toByteArray());
318          msg = new MimeMessage(session, bais);
319          if (PRINT_MESSAGES) {
320        printMessage(msg);
321      }
322          DumpMessage.dumpMsg(msg);
323          
324          System.out.println("\n\n*****************************************\n\n");
325
326      // 6. Now create a explicitly signed and encrypted message with attachment
327      msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), multipart, false);
328      System.out.println("creating explicitly signed and encrypted message [AES/256]...");
329          baos.reset();
330          msg.saveChanges();
331          msg.writeTo(baos);
332          bais = new ByteArrayInputStream(baos.toByteArray());
333          msg = new MimeMessage(session, bais);
334          if (PRINT_MESSAGES) {
335        printMessage(msg);
336      }
337          DumpMessage.dumpMsg(msg);
338          
339          System.out.println("\n\n*****************************************\n\n");
340          
341          // 7. Authenticated encrypted message with several algorithms
342          if (DemoUtil.getIaikProviderVersion() >= 5.62) {
343        msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), 128);
344        System.out.println("creating encrypted message [AESGCM/128]...");
345        baos.reset();
346        msg.saveChanges();
347        msg.writeTo(baos);
348        bais = new ByteArrayInputStream(baos.toByteArray());
349        msg = new MimeMessage(session, bais);
350        if (PRINT_MESSAGES) {
351          printMessage(msg);
352        }
353        DumpMessage.dumpMsg(msg);
354        
355        System.out.println("\n\n*****************************************\n\n");
356        
357        msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_GCM.clone(), 192);
358        System.out.println("creating encrypted message [AESGCM/192]...");
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        msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_GCM.clone(), 256);
372        System.out.println("creating encrypted message [AESGCM/256]...");
373        baos.reset();
374        msg.saveChanges();
375        msg.writeTo(baos);
376        bais = new ByteArrayInputStream(baos.toByteArray());
377        msg = new MimeMessage(session, bais);
378        if (PRINT_MESSAGES) {
379          printMessage(msg);
380        }
381        DumpMessage.dumpMsg(msg);
382        
383        msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), 256);
384        System.out.println("creating encrypted message [ChaCha20Poly1305]...");
385        baos.reset();
386        msg.saveChanges();
387        msg.writeTo(baos);
388        bais = new ByteArrayInputStream(baos.toByteArray());
389        msg = new MimeMessage(session, bais);
390        if (PRINT_MESSAGES) {
391          printMessage(msg);
392        }
393        DumpMessage.dumpMsg(msg);
394        
395        System.out.println("\n\n*****************************************\n\n");
396        
397        msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), 128);
398        System.out.println("creating encrypted message [AESCCM/128]...");
399        baos.reset();
400        msg.saveChanges();
401        msg.writeTo(baos);
402        bais = new ByteArrayInputStream(baos.toByteArray());
403        msg = new MimeMessage(session, bais);
404        if (PRINT_MESSAGES) {
405          printMessage(msg);
406        }
407        DumpMessage.dumpMsg(msg);
408        
409        System.out.println("\n\n*****************************************\n\n");
410        
411        msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CCM.clone(), 192);
412        System.out.println("creating encrypted message [AESCCM/192]...");
413        baos.reset();
414        msg.saveChanges();
415        msg.writeTo(baos);
416        bais = new ByteArrayInputStream(baos.toByteArray());
417        msg = new MimeMessage(session, bais);
418        if (PRINT_MESSAGES) {
419          printMessage(msg);
420        }
421        DumpMessage.dumpMsg(msg);
422        
423        System.out.println("\n\n*****************************************\n\n");
424        
425        msg = createAuthEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CCM.clone(), 256);
426        System.out.println("creating encrypted message [AESCCM/256]...");
427        baos.reset();
428        msg.saveChanges();
429        msg.writeTo(baos);
430        bais = new ByteArrayInputStream(baos.toByteArray());
431        msg = new MimeMessage(session, bais);
432        if (PRINT_MESSAGES) {
433          printMessage(msg);
434        }
435        DumpMessage.dumpMsg(msg);
436        
437        System.out.println("\n\n*****************************************\n\n");
438        
439        // Now create a implicitly signed and authenticated encrypted message with attachment
440        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), multipart, true);
441        System.out.println("creating implicitly signed and authenticated encrypted message [AES-GCM/128]...");
442        baos.reset();
443        msg.saveChanges();
444        msg.writeTo(baos);
445        bais = new ByteArrayInputStream(baos.toByteArray());
446        msg = new MimeMessage(session, bais);
447        if (PRINT_MESSAGES) {
448          printMessage(msg);
449        }
450        DumpMessage.dumpMsg(msg);
451        
452        System.out.println("\n\n*****************************************\n\n");
453
454        // Now create a explicitly signed and authenticated encrypted message with attachment
455        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_GCM.clone(), multipart, false);
456        System.out.println("creating explicitly signed and authenticated encrypted message [AES-GCM/128]...");
457        baos.reset();
458        msg.saveChanges();
459        msg.writeTo(baos);
460        bais = new ByteArrayInputStream(baos.toByteArray());
461        msg = new MimeMessage(session, bais);
462        if (PRINT_MESSAGES) {
463          printMessage(msg);
464        }
465        DumpMessage.dumpMsg(msg);
466        
467        System.out.println("\n\n*****************************************\n\n");
468        
469        // Now create a implicitly signed and authenticated encrypted message with attachment
470        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), multipart, true);
471        System.out.println("creating implicitly signed and authenticated encrypted message [ChaChaPoly1305]...");
472        baos.reset();
473        msg.saveChanges();
474        msg.writeTo(baos);
475        bais = new ByteArrayInputStream(baos.toByteArray());
476        msg = new MimeMessage(session, bais);
477        if (PRINT_MESSAGES) {
478          printMessage(msg);
479        }
480        DumpMessage.dumpMsg(msg);
481        
482        System.out.println("\n\n*****************************************\n\n");
483
484        // Now create a explicitly signed and authenticated encrypted message with attachment
485        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.chacha20Poly1305.clone(), multipart, false);
486        System.out.println("creating explicitly signed and authenticated encrypted message [ChaChaPoly1305]...");
487        baos.reset();
488        msg.saveChanges();
489        msg.writeTo(baos);
490        bais = new ByteArrayInputStream(baos.toByteArray());
491        msg = new MimeMessage(session, bais);
492        if (PRINT_MESSAGES) {
493          printMessage(msg);
494        }
495        DumpMessage.dumpMsg(msg);
496        
497        System.out.println("\n\n*****************************************\n\n");
498        
499        // Now create a implicitly signed and authenticated encrypted message with attachment
500        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), multipart, true);
501        System.out.println("creating implicitly signed and authenticated encrypted message [AES-CCM/128]...");
502        baos.reset();
503        msg.saveChanges();
504        msg.writeTo(baos);
505        bais = new ByteArrayInputStream(baos.toByteArray());
506        msg = new MimeMessage(session, bais);
507        if (PRINT_MESSAGES) {
508          printMessage(msg);
509        }
510        DumpMessage.dumpMsg(msg);
511        
512        System.out.println("\n\n*****************************************\n\n");
513
514        // Now create a explicitly signed and authenticated encrypted message with attachment
515        msg = createSignedAndEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CCM.clone(), multipart, false);
516        System.out.println("creating explicitly signed and authenticated encrypted message [AES-CCM/128]...");
517        baos.reset();
518        msg.saveChanges();
519        msg.writeTo(baos);
520        bais = new ByteArrayInputStream(baos.toByteArray());
521        msg = new MimeMessage(session, bais);
522        if (PRINT_MESSAGES) {
523          printMessage(msg);
524        }
525        DumpMessage.dumpMsg(msg);
526        
527        System.out.println("\n\n*****************************************\n\n");
528          }  
529
530          // 8. certs only message
531          msg = createCertsOnlyMessage(session);
532          System.out.println("creating certs-only message");
533          baos.reset();
534          msg.saveChanges();
535          msg.writeTo(baos);
536          bais = new ByteArrayInputStream(baos.toByteArray());
537          msg = new MimeMessage(session, bais);
538          if (PRINT_MESSAGES) {
539        printMessage(msg);
540      }
541          DumpMessage.dumpMsg(msg);
542          
543          System.out.println("\n\n*****************************************\n\n");
544
545          // 9. certs only message where the cert list is put into the second part
546          msg = createCertsOnlyMultiPartMessage(session);
547          System.out.println("creating message with certs-only part");
548          baos.reset();
549          msg.saveChanges();
550          msg.writeTo(baos);
551          bais = new ByteArrayInputStream(baos.toByteArray());
552          msg = new MimeMessage(session, bais);
553          if (PRINT_MESSAGES) {
554        printMessage(msg);
555      }
556          DumpMessage.dumpMsg(msg);
557          
558          System.out.println("\n\n*****************************************\n\n");
559
560          // 10. application/pkcs10 cert request message
561      msg = createPKCS10Message(session);
562      System.out.println("creating application/pkcs10 message...");
563          baos.reset();
564          msg.saveChanges();
565          msg.writeTo(baos);
566          bais = new ByteArrayInputStream(baos.toByteArray());
567          msg = new MimeMessage(session, bais);
568          if (PRINT_MESSAGES) {
569        printMessage(msg);
570      }
571          DumpMessage.dumpMsg(msg);
572          
573          System.out.println("\n\n*****************************************\n\n");
574
575          // 11. application/pkcs10 message where the request is in the second part
576          msg = createPKCS10MultiPartMessage(session);
577          System.out.println("creating message with pkcs10 part...");
578          baos.reset();
579          msg.saveChanges();
580          msg.writeTo(baos);
581          bais = new ByteArrayInputStream(baos.toByteArray());
582          msg = new MimeMessage(session, bais);
583          if (PRINT_MESSAGES) {
584        printMessage(msg);
585      }
586          DumpMessage.dumpMsg(msg);
587          
588          System.out.println("\n\n*****************************************\n\n");
589
590          // 12. compressed message 
591          msg = createCompressedMessage(session, multipart, (AlgorithmID)CMSAlgorithmID.zlib_compress.clone());
592          System.out.println("creating message with compressed data...");
593          baos.reset();
594          msg.saveChanges();
595          msg.writeTo(baos);
596          bais = new ByteArrayInputStream(baos.toByteArray());
597          msg = new MimeMessage(session, bais);
598          if (PRINT_MESSAGES) {
599        printMessage(msg);
600      }
601          DumpMessage.dumpMsg(msg);
602
603        } catch (Exception ex) {
604            ex.printStackTrace();
605            throw new RuntimeException(ex.toString());
606        }
607  }
608  
609  /**
610   * Creates a MIME message container with the given subject for the given session.
611   * 
612   * @param session the mail sesion
613   * @param subject the subject of the message
614   *
615   * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
616   *
617   * @throws MessagingException if the message cannot be created
618   */
619  public Message createMessage(Session session, String subject) throws MessagingException {
620    MimeMessage msg = new MimeMessage(session);
621    msg.setFrom(new InternetAddress(from_));
622        msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to_, false));
623        msg.setSentDate(new Date());
624    msg.setSubject(subject);
625    return msg;
626  }
627  
628  /**
629   * Creates a simple plain (neither signed nor encrypted) message.
630   *
631   * @param session the mail session
632   * @param dataHandler the content of the message
633   * 
634   * @return the plain message
635   *
636   * @throws MessagingException if an error occurs when creating the message
637   */
638  public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException {
639
640    Message msg = createMessage(session, "IAIK-S/MIME: Plain message");
641    if (dataHandler != null) {
642      msg.setDataHandler(dataHandler);
643    } else {
644      msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n");
645    }
646        return msg;
647  }
648  
649  /**
650   * Creates a signed and encrypted message.
651   *
652   * @param session the mail session
653   * @param algorithm the content encryption algorithm to be used
654   * @param dataHandler the content of the message to be signed and encrypted
655   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
656   *                 (multipart/signed) signing
657   * 
658   * @return the signed and encrypted message
659   *
660   * @throws MessagingException if an error occurs when creating the message
661   */
662  public Message createSignedAndEncryptedMessage(Session session, AlgorithmID algorithm, DataHandler dataHandler, boolean implicit)
663    throws MessagingException {
664
665    String subject = null;
666    String text = null;
667    if (implicit) {
668      subject = "IAIK-S/MIME: Implicitly Signed and Encrypted";
669      text = "This message is implicitly signed and encrypted!\n\n\n";
670    } else {
671      subject = "IAIK-S/MIME: Explicitly Signed and Encrypted";
672      text = "This message is explicitly signed and encrypted!\n\n\n";
673    }
674    Message msg = createMessage(session, subject);
675
676    SignedContent sc = new SignedContent(implicit);
677    if (dataHandler != null) {
678      sc.setDataHandler(dataHandler);
679    } else {
680      sc.setText(text);
681    }
682    sc.setCertificates(signerCertificates_);
683    try {
684      sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_);
685    } catch (NoSuchAlgorithmException ex) {
686      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
687    }
688
689    EncryptedContent ec = null;
690    if (algorithm.equals(AlgorithmID.aes256_CBC)) {
691      ec = new EncryptedContent(sc);
692    } else {
693      ec = new AuthEncryptedContent(sc);
694    }
695    // encrypt for the recipient
696    ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
697    // I want to be able to decrypt the message, too
698    ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
699    // set the encryption algorithm
700    try {
701      ec.setEncryptionAlgorithm(algorithm, -1);
702    } catch (NoSuchAlgorithmException ex) {
703      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
704    }   
705    msg.setContent(ec, ec.getContentType());
706    // let the EncryptedContent update some message headers
707    ec.setHeaders(msg);
708
709    return msg;
710  }
711  
712  
713  
714  /**
715   * Creates a signed message.
716   *
717   * @param session the mail session
718   * @param dataHandler the content of the message to be signed
719   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
720   *                 (multipart/signed) signing
721   * 
722   * @return the signed message
723   *
724   * @throws MessagingException if an error occurs when creating the message
725   */
726  public Message createSignedMessage(Session session, DataHandler dataHandler, boolean implicit)
727      throws MessagingException {
728
729    String subject = null;
730    StringBuffer buf = new StringBuffer();
731    
732    if (implicit) {
733      subject = "IAIK-S/MIME: Implicitly Signed";
734      buf.append("This message is implicitly signed!\n");
735      buf.append("You need an S/MIME aware mail client to view this message.\n");
736      buf.append("\n\n");
737    } else {
738      subject = "IAIK-S/MIME: Explicitly Signed";
739      buf.append("This message is explicitly signed!\n");
740      buf.append("Every mail client can view this message.\n");
741      buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
742      buf.append("\n\n");
743    }
744    
745    Message msg = createMessage(session, subject);
746
747    SignedContent sc = new SignedContent(implicit);
748
749    if (dataHandler != null) {
750      sc.setDataHandler(dataHandler);
751    } else {
752      sc.setText(buf.toString());
753    }
754    sc.setCertificates(signerCertificates_);
755
756    try {
757      sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_);
758    } catch (NoSuchAlgorithmException ex) {
759      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
760    }
761
762    msg.setContent(sc, sc.getContentType());
763    // let the SignedContent update some message headers
764    sc.setHeaders(msg);
765    return msg;
766  }
767  
768  /**
769   * Creates an encrypted message.
770   *
771   * @param session the mail session
772   * @param algorithm the content encryption algorithm to be used
773   * @param keyLength the length of the secret content encryption key to be created and used
774   * 
775   * @return the encrypted message
776   *
777   * @throws MessagingException if an error occurs when creating the message
778   */
779  public Message createEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength)
780      throws MessagingException {
781
782    StringBuffer subject = new StringBuffer();
783    subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName());
784    if (keyLength > 0) {
785      subject.append("/"+keyLength);
786    }  
787    subject.append("]");
788    Message msg = createMessage(session, subject.toString());
789
790    EncryptedContent ec = new EncryptedContent();
791
792    StringBuffer buf = new StringBuffer();
793    buf.append("This is the encrypted content!\n");
794    buf.append("Content encryption algorithm: "+algorithm.getName());
795    buf.append("\n\n");
796
797    ec.setText(buf.toString());
798    // encrypt for the recipient
799    ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
800    // I want to be able to decrypt the message, too
801    ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
802    try {
803      ec.setEncryptionAlgorithm(algorithm, keyLength);
804    } catch (NoSuchAlgorithmException ex) {
805      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
806    }   
807
808    msg.setContent(ec, ec.getContentType());
809    // let the EncryptedContent update some message headers
810    ec.setHeaders(msg);
811
812    return msg;
813  }
814  
815  /**
816   * Creates an authenticated encrypted message.
817   *
818   * @param session the mail session
819   * @param algorithm the content encryption algorithm to be used
820   * @param keyLength the length of the secret content encryption key to be created and used
821   * 
822   * @return the encrypted message
823   *
824   * @throws MessagingException if an error occurs when creating the message
825   */
826  public Message createAuthEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength)
827      throws MessagingException {
828
829    StringBuffer subject = new StringBuffer();
830    subject.append("IAIK-S/MIME: AuthEncrypted ["+algorithm.getName());
831    if (keyLength > 0) {
832      subject.append("/"+keyLength);
833    }  
834    subject.append("]");
835    Message msg = createMessage(session, subject.toString());
836
837    AuthEncryptedContent ec = new AuthEncryptedContent();
838
839    StringBuffer buf = new StringBuffer();
840    buf.append("This is the authenticated encrypted content!\n");
841    buf.append("Content encryption algorithm: "+algorithm.getName());
842    buf.append("\n\n");
843
844    ec.setText(buf.toString());
845    // encrypt for the recipient
846    ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
847    // I want to be able to decrypt the message, too
848    ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
849    try {
850      ec.setEncryptionAlgorithm(algorithm, keyLength);
851    } catch (NoSuchAlgorithmException ex) {
852      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
853    }   
854
855    msg.setContent(ec, ec.getContentType());
856    // let the EncryptedContent update some message headers
857    ec.setHeaders(msg);
858
859    return msg;
860  }
861  
862  /**
863   * Creates a certs-only message.
864   *
865   * @param session the mail session
866   * 
867   * @return the certs-only message
868   *
869   * @throws MessagingException if an error occurs when creating the message
870   */
871  public Message createCertsOnlyMessage(Session session)
872      throws MessagingException {
873
874    Message msg = createMessage(session, "IAIK S/MIME: Certs-only message");
875    //use new content types
876    SMimeParameters.useNewContentTypes(true);
877    SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
878    sc.setCertificates(signerCertificates_);
879    msg.setContent(sc, sc.getContentType());
880    //set filename and attachment parameters
881    sc.setHeaders(msg);
882
883
884    return msg;
885  }
886  
887  /**
888   * Creates a certs-only message where the certificate list is transferred as attachment.
889   *
890   * @param session the mail session
891   * 
892   * @return the certs-only message
893   *
894   * @throws MessagingException if an error occurs when creating the message
895   */
896  public Message createCertsOnlyMultiPartMessage(Session session) throws MessagingException {
897
898    MimeBodyPart mbp1 = new MimeBodyPart();
899        mbp1.setText("This is a test where the certs-only message is included in the second part!\n\n");
900
901    MimeBodyPart attachment = new MimeBodyPart();
902    //use new content types
903    SMimeParameters.useNewContentTypes(true);
904    SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
905    sc.setCertificates(signerCertificates_);
906    attachment.setContent(sc, sc.getContentType());
907    // let the SignedContent update some headers
908    sc.setHeaders(attachment);
909    Multipart mp = new MimeMultipart();
910    mp.addBodyPart(mbp1);
911    mp.addBodyPart(attachment);
912
913    Message msg = createMessage(session, "IAIK S/MIME: Certs-only multipart message");
914    msg.setContent(mp, mp.getContentType());
915
916    return msg;
917  }
918  
919  /**
920   * Creates a compressed message.
921   *
922   * @param session the mail session
923   * @param dataHandler the datahandler supplying the content to be compressed
924   * @param algorithm the compression algorithm to be used
925   * 
926   * @return the compressed message
927   *
928   * @throws MessagingException if an error occurs when creating the message
929   */
930  public Message createCompressedMessage(Session session, DataHandler dataHandler, AlgorithmID algorithm)
931      throws MessagingException {
932
933    String subject = "IAIK-S/MIME: Compressed ["+algorithm.getName()+"]";
934    Message msg = createMessage(session, subject.toString());
935
936    CompressedContent compressedContent = new CompressedContent();
937    
938    if (dataHandler == null) {
939      StringBuffer buf = new StringBuffer();
940      buf.append("This is the compressed content!\n");
941      buf.append("Compression algorithm: "+algorithm.getName());
942      buf.append("\n\n");
943      compressedContent.setText(buf.toString());
944    } else {
945      compressedContent.setDataHandler(dataHandler);   
946    }    
947    
948    try {
949      compressedContent.setCompressionAlgorithm(algorithm);
950    } catch (NoSuchAlgorithmException ex) {
951      throw new MessagingException("Compression algorithm not supported: " + ex.getMessage());   
952    }   
953
954    msg.setContent(compressedContent, compressedContent.getContentType());
955    // let the CompressedContent update some message headers
956    compressedContent.setHeaders(msg);
957
958    return msg;
959  }
960  
961  /**
962   * Creates a PKCS#10 certificate request message.
963   *
964   * @param session the mail session
965   * 
966   * @return the PKCS#10 certificate request message
967   *
968   * @throws MessagingException if an error occurs when creating the message
969   */
970  public Message createPKCS10Message(Session session)
971    throws MessagingException {
972
973    Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request");
974
975    PKCS10Content pc = new PKCS10Content();
976    CertificateRequest request = null;
977    try {
978       request = createCertificateRequest();
979    } catch (PKCSException ex) {
980       throw new MessagingException(ex.getMessage());
981    }
982    pc.setCertRequest(request);
983    msg.setContent(pc, pc.getContentType());
984    // let the PKCS10Content update some message headers
985    pc.setHeaders(msg);
986
987    return msg;
988  }
989  
990    /**
991   * Creates a PKCS#10 message where the certificate request is transferred as attachment.
992   *
993   * @param session the mail session
994   * 
995   * @return the PKCS#10 certificate request message
996   *
997   * @throws MessagingException if an error occurs when creating the message
998   */
999  public Message createPKCS10MultiPartMessage(Session session) throws MessagingException {
1000
1001    MimeBodyPart mbp1 = new MimeBodyPart();
1002        mbp1.setText("This is a test where the request message is included in the second part!\n\n");
1003        // try to test an attachment
1004        // this demo attaches our homepage
1005    MimeBodyPart attachment = new MimeBodyPart();
1006    //use new content types
1007    SMimeParameters.useNewContentTypes(true);
1008    PKCS10Content pc = new PKCS10Content();
1009    CertificateRequest request = null;
1010    try {
1011       request = createCertificateRequest();
1012    } catch (PKCSException ex) {
1013       throw new MessagingException(ex.getMessage());
1014    }
1015    pc.setCertRequest(request);
1016    DataHandler pkcs10Handler = new DataHandler(pc, pc.getContentType());
1017    attachment.setDataHandler(pkcs10Handler);
1018    attachment.setDisposition("attachment");
1019    attachment.setFileName("smime.p10");
1020    Multipart mp = new MimeMultipart();
1021    mp.addBodyPart(mbp1);
1022    mp.addBodyPart(attachment);
1023
1024    Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request multipart message");
1025    msg.setContent(mp, mp.getContentType());
1026    return msg;
1027  }
1028  
1029  /**
1030   * Creates a PKCS#10 certificate request.
1031   *
1032   * @return the certificate request
1033   *
1034   * @throws PKCSException if the request cannot be created
1035   */
1036  private CertificateRequest createCertificateRequest() throws PKCSException {
1037    try {
1038      Name subject = new Name();
1039          subject.addRDN(ObjectID.commonName, firstName_ + " " + lastName_);
1040          subject.addRDN(ObjectID.emailAddress, from_);
1041          CertificateRequest certRequest;
1042
1043      certRequest = new CertificateRequest(signerCertificate_.getPublicKey(), subject);
1044          certRequest.sign((AlgorithmID)AlgorithmID.sha256WithRSAEncryption.clone(), signerPrivateKey_);
1045          certRequest.verify();
1046          return certRequest;
1047        } catch (Exception ex) {
1048          throw new PKCSException("Cannot create cert request: " + ex.getMessage());
1049        }
1050  }
1051  
1052  
1053  /** 
1054   * Prints a dump of the given message to System.out.
1055   *
1056   * @param msg the message to be dumped to System.out
1057   */
1058  static void printMessage(Message msg) throws IOException {
1059    System.out.println("------------------------------------------------------------------");
1060    System.out.println("Message dump: \n");
1061    try {
1062      msg.writeTo(System.out);
1063    } catch (MessagingException ex) {
1064      throw new IOException(ex.getMessage());   
1065    }    
1066    System.out.println("\n------------------------------------------------------------------");
1067  }  
1068
1069
1070  /**
1071   * The main method.
1072   */
1073  public static void main(String[] argv) throws IOException {
1074
1075    DemoSMimeUtil.initDemos();
1076        (new SMimeDemo()).start();
1077    System.out.println("\nReady!");
1078    DemoUtil.waitKey();
1079  }
1080}