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/SMimeSendDemo.java 38    12.02.25 17:58 Dbratko $
029// $Revision: 38 $
030//
031
032package demo.smime.basic;
033
034import iaik.asn1.ObjectID;
035import iaik.asn1.structures.AlgorithmID;
036import iaik.asn1.structures.Name;
037import iaik.pkcs.PKCSException;
038import iaik.pkcs.pkcs10.CertificateRequest;
039import iaik.smime.EncryptedContent;
040import iaik.smime.PKCS10Content;
041import iaik.smime.SMimeBodyPart;
042import iaik.smime.SMimeMultipart;
043import iaik.smime.SMimeParameters;
044import iaik.smime.SignedContent;
045import iaik.x509.X509Certificate;
046
047import java.io.IOException;
048import java.security.NoSuchAlgorithmException;
049import java.security.PrivateKey;
050import java.security.interfaces.RSAPrivateKey;
051import java.util.Date;
052
053import jakarta.activation.DataHandler;
054import jakarta.activation.FileDataSource;
055import jakarta.mail.Message;
056import jakarta.mail.MessagingException;
057import jakarta.mail.Multipart;
058import jakarta.mail.Session;
059import jakarta.mail.Transport;
060import jakarta.mail.internet.InternetAddress;
061import jakarta.mail.internet.MimeBodyPart;
062import jakarta.mail.internet.MimeMessage;
063import jakarta.mail.internet.MimeMultipart;
064
065import demo.DemoSMimeUtil;
066import demo.DemoUtil;
067import demo.keystore.CMSKeyStore;
068
069/**
070 * This class demonstrates the usage of the IAIK S/MIME implementation for sending
071 * signed and/or encryped emails based on the Jakarta Mail API. 
072 * <p>
073 * To run this demo the following packages are required:
074 * <ul>
075 *    <li>
076 *       <code>iaik_cms.jar</code> (IAIK-CMS/SMIME)
077 *    </li>
078 *    <li>
079 *       <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>).
080 *    </li>
081 *    <li>
082 *       <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
083 *    </li>   
084 *    <li>
085 *       <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a>
086 *    </li> 
087 * </ul>
088 * 
089 * <b>Usage:</b>
090 * <pre>
091 * SMimeSend [-H host] [-S sender name] [-F (From) sender address] [-T (To) recipient address]
092 * </pre>
093 * <b>Example</b>:
094 * <pre>
095 * SMimeSend -H mailhost -S \"John SMime\" -F smimetest@iaik.tugraz.at -T smimetest@iaik.tugraz.at
096 * </pre>
097 * By default this demo used "mailhost" as host, "John SMime" as sender name, and "smimetest@iaik.tugraz.at"
098 * as sender and also as recipient mail address. "smimetest@iaik.tugraz.at" is also the email address
099 * contained in the demo certificates. Although you should specify other email addresses to send
100 * the test messages to yourself, be aware that the certificate email check may fail on the
101 * receiving side ({@link SMimeShowDemo SMimeShowDemo}).
102 *
103 * @see iaik.smime.EncryptedContent
104 * @see iaik.smime.SignedContent
105 */
106public class SMimeSendDemo {
107
108  String senderName_ = "John SMime";
109  String to_ = "smimetest@iaik.tugraz.at";     // email recipient
110  String from_ = "smimetest@iaik.tugraz.at";   // email sender
111  String host_ = "mailhost";                   // name of the mailhost
112
113  X509Certificate[] signerCertificates_;    // list of certificates to include in the S/MIME message
114  X509Certificate recipientCertificate_;    // certificate of the recipient
115  X509Certificate signerCertificate_;       // certificate of the signer/sender
116  X509Certificate encryptionCertOfSigner_;  // signer uses different certificate for encryption
117  PrivateKey signerPrivateKey_;             // private key of the signer/sender
118  
119  /**
120   * Default constructor. Reads certificates and keys from the demo keystore.
121   */
122  public SMimeSendDemo() {
123    
124    System.out.println();
125    System.out.println("******************************************************************************************");
126    System.out.println("*                                 SMimeSend demo                                         *");
127    System.out.println("*         (shows how to create and send signed and encrypted S/MIME messages)            *");
128    System.out.println("******************************************************************************************");
129    System.out.println();
130    
131    // get the certificates from the KeyStore
132    signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
133    signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
134    signerCertificate_ = signerCertificates_[0];
135
136    // recipient = signer for this test
137    recipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
138    encryptionCertOfSigner_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
139    
140    // send the encryption cert of the signer along with the signer certificates
141    X509Certificate[] tmpCerts = new X509Certificate[signerCertificates_.length + 1];
142    System.arraycopy(signerCertificates_, 0, tmpCerts, 0, signerCertificates_.length);
143    tmpCerts[signerCertificates_.length] = encryptionCertOfSigner_;
144    signerCertificates_ = tmpCerts;
145  }
146  
147  /**
148   * Starts the demo.
149   *
150   *
151   * @param argv optional parameters like mailhost, sender name,...
152   * 
153   * @throws IOException if an I/O related error occurs
154   */
155  public void start(String[] argv) throws IOException {
156    
157    int optind = 0;
158    if (argv.length > 0) {
159      for (optind = 0; optind < argv.length; optind++) {
160        if (argv[optind].equals("-H")) {
161          host_ = argv[++optind];
162        } else if (argv[optind].equals("-S")) {
163          senderName_ = argv[++optind];
164        } else if (argv[optind].equals("-F")) {
165          from_ = argv[++optind];
166        } else if (argv[optind].equals("-T")) {
167          to_ = argv[++optind];
168        } else {
169          System.out.println("Usage: SMimeSend [-H host] [-S sender name] [-F (From) sender address] [-T (To) recipient address]");
170          System.out.println("e.g.:");
171          System.out.println("Usage: SMimeSend -H mailhost -S \"John SMime\" -F smimetest@iaik.tugraz.at -T smimetest@iaik.tugraz.at");
172          System.exit(1);
173        } 
174      }  
175    } 
176
177
178    // get the default Session
179        Session session = DemoSMimeUtil.getSession(host_);
180
181        try {
182      // Create a demo Multipart
183      MimeBodyPart mbp1 = new SMimeBodyPart();
184          mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
185      // try to test an attachment
186      MimeBodyPart attachment = new SMimeBodyPart();
187      attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
188      attachment.setFileName("test.html");
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
196      // 1. This is a plain message
197      msg = createPlainMessage(session, multipart);
198      System.out.println("sending plain message...");
199          Transport.send(msg);
200
201      // 2. This is an explicitly signed message
202      msg = createSignedMessage(session, multipart, false);
203      System.out.println("sending explicitly signed message...");
204          Transport.send(msg);
205
206      // 3. This is an implicitly signed message
207      msg = createSignedMessage(session, multipart, true);
208      System.out.println("sending implicitly signed message...");
209          Transport.send(msg);
210
211      // 4. Now create encrypted messages with different content encryption algorithms
212          // RC2 is deprecated; only demonstrated here
213      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 40);
214      System.out.println("sending encrypted message [RC2/40]...");
215          Transport.send(msg);
216      
217      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 64);
218      System.out.println("sending encrypted message [RC2/64]...");
219          Transport.send(msg);
220      
221      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.rc2_CBC.clone(), 128);
222      System.out.println("sending encrypted message [RC2/128]...");
223          Transport.send(msg);
224      
225          // TripleDES is deprecated; only demonstrated here
226      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.des_EDE3_CBC.clone(), 192);
227      System.out.println("sending encrypted message [TripleDES]...");
228          Transport.send(msg);
229          
230          msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes128_CBC.clone(), 128);
231      System.out.println("sending encrypted message [AES-128]...");
232      Transport.send(msg);
233      
234      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes192_CBC.clone(), 192);
235      System.out.println("sending encrypted message [AES-192]...");
236      Transport.send(msg);
237      
238      msg = createEncryptedMessage(session, (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256);
239      System.out.println("sending encrypted message [AES-256]...");
240      Transport.send(msg);
241
242      // 5. Now create a implicitly signed and encrypted message with attachment
243      msg = createSignedAndEncryptedMessage(session, multipart, true);
244      System.out.println("sending implicitly signed and encrypted message [AES-256]...");
245          Transport.send(msg);
246
247      // 6. Now create a explicitly signed and encrypted message with attachment
248      msg = createSignedAndEncryptedMessage(session, multipart, false);
249      System.out.println("sending explicitly signed and encrypted message [AES-256]...");
250          Transport.send(msg);
251
252          // 7. certs only message
253          msg = createCertsOnlyMessage(session);
254          System.out.println("sending certs-only message");
255          Transport.send(msg);
256
257          // 8. second certs only message
258          msg = createCertsOnlyMultiPartMessage(session);
259          System.out.println("sending message with certs-only part");
260          Transport.send(msg);
261
262          //sending cert request
263      msg = createPKCS10Message(session);
264      System.out.println("sending application/pkcs10 message...");
265          Transport.send(msg);
266
267          // ending application/pkcs10 message where the request is in the second part
268          msg = createPKCS10MultiPartMessage(session);
269          System.out.println("sending message with pkcs10 part...");
270          Transport.send(msg);
271
272        } catch (MessagingException mex) {
273      mex.printStackTrace();
274          Exception ex = null;
275          if ((ex = mex.getNextException()) != null) {
276        ex.printStackTrace();
277          }
278          throw new RuntimeException(mex.toString());
279        }
280
281  }
282  
283  /**
284   * Creates a MIME message container with the given subject for the given session.
285   * 
286   * @param session the mail sesion
287   * @param subject the subject of the message
288   *
289   * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
290   *
291   * @throws MessagingException if the message cannot be created
292   */
293  public Message createMessage(Session session, String subject) throws MessagingException {
294    MimeMessage msg = new MimeMessage(session);
295    msg.setFrom(new InternetAddress(from_));
296        msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to_, false));
297        msg.setSentDate(new Date());
298    msg.setSubject(subject);
299    return msg;
300  }
301  
302  /**
303   * Creates a simple plain (neither signed nor encrypted) message.
304   *
305   * @param session the mail session
306   * @param dataHandler the content of the message
307   * 
308   * @return the plain message
309   *
310   * @throws MessagingException if an error occurs when creating the message
311   */
312  public Message createPlainMessage(Session session, DataHandler dataHandler) throws MessagingException {
313
314    Message msg = createMessage(session, "IAIK-S/MIME: Plain message");
315    if (dataHandler != null) {
316      msg.setDataHandler(dataHandler);
317    } else {
318      msg.setText("This is a plain message!\nIt is wether signed nor encrypted!\n");
319    }
320    return msg;
321  }
322
323  /**
324   * Creates a signed and encrypted message.
325   *
326   * @param session the mail session
327   * @param dataHandler the content of the message to be signed and encrypted
328   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
329   *                 (multipart/signed) signing
330   * 
331   * @return the signed and encrypted message
332   *
333   * @throws MessagingException if an error occurs when creating the message
334   */
335  public Message createSignedAndEncryptedMessage(Session session, DataHandler dataHandler, boolean implicit)
336    throws MessagingException {
337
338    String subject = null;
339    String text = null;
340    if (implicit) {
341      subject = "IAIK-S/MIME: Implicitly Signed and Encrypted";
342      text = "This message is implicitly signed and encrypted!\n\n\n";
343    } else {
344      subject = "IAIK-S/MIME: Explicitly Signed and Encrypted";
345      text = "This message is explicitly signed and encrypted!\n\n\n";
346    }
347    Message msg = createMessage(session, subject);
348
349    SignedContent sc = new SignedContent(implicit);
350    if (dataHandler != null) {
351      sc.setDataHandler(dataHandler);
352    } else {
353      sc.setText(text);
354    }
355    sc.setCertificates(signerCertificates_);
356    try {
357      sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_, encryptionCertOfSigner_, true);
358    } catch (NoSuchAlgorithmException ex) {
359      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
360    }
361
362    EncryptedContent ec = new EncryptedContent(sc);
363    // encrypt for the recipient
364    ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
365    // I want to be able to decrypt the message, too
366    ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
367    // set the encryption algorithm
368    try {
369      ec.setEncryptionAlgorithm((AlgorithmID)AlgorithmID.aes256_CBC.clone(), 256);
370    } catch (NoSuchAlgorithmException ex) {
371      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
372    }   
373    msg.setContent(ec, ec.getContentType());
374    // let the EncryptedContent update some message headers
375    ec.setHeaders(msg);
376
377    return msg;
378  }
379  
380  /**
381   * Creates a signed message.
382   *
383   * @param session the mail session
384   * @param dataHandler the content of the message to be signed
385   * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
386   *                 (multipart/signed) signing
387   * 
388   * @return the signed message
389   *
390   * @throws MessagingException if an error occurs when creating the message
391   */
392  public Message createSignedMessage(Session session, DataHandler dataHandler, boolean implicit)
393      throws MessagingException {
394
395    String subject = null;
396    StringBuffer buf = new StringBuffer();
397    
398    if (implicit) {
399      subject = "IAIK-S/MIME: Implicitly Signed";
400      buf.append("This message is implicitly signed!\n");
401      buf.append("You need an S/MIME aware mail client to view this message.\n");
402      buf.append("\n\n");
403    } else {
404      subject = "IAIK-S/MIME: Explicitly Signed";
405      buf.append("This message is explicitly signed!\n");
406      buf.append("Every mail client can view this message.\n");
407      buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
408      buf.append("\n\n");
409    }
410    
411    Message msg = createMessage(session, subject);
412    
413    SignedContent sc = new SignedContent(implicit);
414    if (dataHandler != null) {
415      sc.setDataHandler(dataHandler);
416    } else {
417      sc.setText(buf.toString());
418    }
419    sc.setCertificates(signerCertificates_);
420
421    try {
422      sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_, encryptionCertOfSigner_, true);
423    } catch (NoSuchAlgorithmException ex) {
424      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
425    }
426
427    msg.setContent(sc, sc.getContentType());
428    // let the SignedContent update some message headers
429    sc.setHeaders(msg);
430    return msg;
431  }
432  
433  /**
434   * Creates an encrypted message.
435   *
436   * @param session the mail session
437   * @param algorithm the content encryption algorithm to be used
438   * @param keyLength the length of the secret content encryption key to be created and used
439   * 
440   * @return the encrypted message
441   *
442   * @throws MessagingException if an error occurs when creating the message
443   */
444  public Message createEncryptedMessage(Session session, AlgorithmID algorithm, int keyLength)
445      throws MessagingException {
446
447    StringBuffer subject = new StringBuffer();
448    subject.append("IAIK-S/MIME: Encrypted ["+algorithm.getName());
449    if (keyLength > 0) {
450      subject.append("/"+keyLength);
451    }  
452    subject.append("]");
453    Message msg = createMessage(session, subject.toString());
454
455    EncryptedContent ec = new EncryptedContent();
456
457    StringBuffer buf = new StringBuffer();
458    buf.append("This is the encrypted content!\n");
459    buf.append("Content encryption algorithm: "+algorithm.getName());
460    buf.append("\n\n");
461
462    ec.setText(buf.toString());
463    // encrypt for the recipient
464    ec.addRecipient(recipientCertificate_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
465    // I want to be able to decrypt the message, too
466    ec.addRecipient(encryptionCertOfSigner_, (AlgorithmID)AlgorithmID.rsaEncryption.clone());
467    try {
468      ec.setEncryptionAlgorithm(algorithm, keyLength);
469    } catch (NoSuchAlgorithmException ex) {
470      throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
471    }   
472
473    msg.setContent(ec, ec.getContentType());
474    // let the EncryptedContent update some message headers
475    ec.setHeaders(msg);
476
477    return msg;
478  }
479  
480  /**
481   * Creates a certs-only message.
482   *
483   * @param session the mail session
484   * 
485   * @return the certs-only message
486   *
487   * @throws MessagingException if an error occurs when creating the message
488   */
489  public Message createCertsOnlyMessage(Session session)
490      throws MessagingException {
491
492    Message msg = createMessage(session, "IAIK S/MIME: Certs-only message");
493    //use new content types
494    SMimeParameters.useNewContentTypes(true);
495    SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
496    sc.setCertificates(signerCertificates_);
497    msg.setContent(sc, sc.getContentType());
498    //set filename and attachment parameters
499    sc.setHeaders(msg);
500
501
502    return msg;
503  }
504
505  
506  /**
507   * Creates a certs-only message where the certificate list is transferred as attachment.
508   *
509   * @param session the mail session
510   * 
511   * @return the certs-only message
512   *
513   * @throws MessagingException if an error occurs when creating the message
514   */
515  public Message createCertsOnlyMultiPartMessage(Session session) throws MessagingException {
516
517    MimeBodyPart mbp1 = new MimeBodyPart();
518        mbp1.setText("This is a test where the certs-only message is included in the second part!\n\n");
519
520    MimeBodyPart attachment = new MimeBodyPart();
521    //use new content types
522    SMimeParameters.useNewContentTypes(true);
523    SignedContent sc = new SignedContent(true, SignedContent.CERTS_ONLY);
524    sc.setCertificates(signerCertificates_);
525    attachment.setContent(sc, sc.getContentType());
526    // let the SignedContent update some message headers
527    sc.setHeaders(attachment);
528    Multipart mp = new MimeMultipart();
529    mp.addBodyPart(mbp1);
530    mp.addBodyPart(attachment);
531
532    Message msg = createMessage(session, "IAIK S/MIME: Certs-only multipart message");
533    msg.setContent(mp, mp.getContentType());
534    return msg;
535  }
536  
537    
538  /**
539   * Creates a PKCS#10 certificate request message.
540   *
541   * @param session the mail session
542   * 
543   * @return the PKCS#10 certificate request message
544   *
545   * @throws MessagingException if an error occurs when creating the message
546   */  
547  public Message createPKCS10Message(Session session)
548    throws MessagingException {
549
550    Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request");
551
552    PKCS10Content pc = new PKCS10Content();
553    CertificateRequest request = null;
554    try {
555       request = createCertificateRequest();
556    } catch (PKCSException ex) {
557       throw new MessagingException(ex.getMessage());
558    }
559    pc.setCertRequest(request);
560    msg.setContent(pc, pc.getContentType());
561    // let the PKCS10Content update some message headers
562    pc.setHeaders(msg);
563
564    return msg;
565  }
566
567  /**
568   * Creates a PKCS#10 certificate request.
569   *
570   * @return the certificate request
571   *
572   * @throws PKCSException if the request cannot be created
573   */
574  private CertificateRequest createCertificateRequest() throws PKCSException {
575    try {
576      Name subject = new Name();
577          subject.addRDN(ObjectID.commonName, senderName_);
578          subject.addRDN(ObjectID.emailAddress, from_);
579          CertificateRequest certRequest;
580
581      certRequest = new CertificateRequest(signerCertificate_.getPublicKey(), subject);
582          certRequest.sign((AlgorithmID)AlgorithmID.sha256WithRSAEncryption.clone(), signerPrivateKey_);
583          certRequest.verify();
584          return certRequest;
585        } catch (Exception ex) {
586          throw new PKCSException("Cannot create cert request: " + ex.getMessage());
587        }
588
589  }
590  
591  /**
592   * Creates a PKCS#10 message where the certificate request is transferred as attachment.
593   *
594   * @param session the mail session
595   * 
596   * @return the PKCS#10 certificate request message
597   *
598   * @throws MessagingException if an error occurs when creating the message
599   */
600  public Message createPKCS10MultiPartMessage(Session session) throws MessagingException {
601
602      MimeBodyPart mbp1 = new MimeBodyPart();
603          mbp1.setText("This is a test where the request message is included in the second part!\n\n");
604          // try to test an attachment
605          // this demo attaches our homepage
606      MimeBodyPart attachment = new MimeBodyPart();
607      //use new content types
608      SMimeParameters.useNewContentTypes(true);
609      PKCS10Content pc = new PKCS10Content();
610      CertificateRequest request = null;
611      try {
612         request = createCertificateRequest();
613      } catch (PKCSException ex) {
614         throw new MessagingException(ex.getMessage());
615      }
616      pc.setCertRequest(request);
617      DataHandler pkcs10Handler = new DataHandler(pc, pc.getContentType());
618      attachment.setDataHandler(pkcs10Handler);
619      attachment.setDisposition("attachment");
620      attachment.setFileName("smime.p10");
621      Multipart mp = new MimeMultipart();
622      mp.addBodyPart(mbp1);
623      mp.addBodyPart(attachment);
624
625      Message msg = createMessage(session, "IAIK-S/MIME: Certificate Request multipart message");
626      msg.setContent(mp, mp.getContentType());
627      return msg;
628  }
629
630
631  /** 
632   * Main method.
633   */
634  public static void main(String[] argv) throws IOException {
635
636    DemoSMimeUtil.initDemos();
637        (new SMimeSendDemo()).start(argv);
638    System.out.println("\nReady!");
639    DemoUtil.waitKey();
640  }
641}