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/BinarySignedDemo.java 22    12.02.25 17:58 Dbratko $
029// $Revision: 22 $
030//
031
032package demo.smime.basic;
033
034import iaik.smime.BinaryCanonicalizer;
035import iaik.smime.DefaultCanonicalizer;
036import iaik.smime.SMimeBodyPart;
037import iaik.smime.SMimeMultipart;
038import iaik.smime.SMimeParameters;
039import iaik.smime.SignedContent;
040import iaik.x509.X509Certificate;
041
042import java.io.ByteArrayInputStream;
043import java.io.ByteArrayOutputStream;
044import java.io.IOException;
045import java.security.NoSuchAlgorithmException;
046import java.security.PrivateKey;
047import java.security.interfaces.RSAPrivateKey;
048import java.util.Date;
049
050import jakarta.activation.DataHandler;
051import jakarta.activation.FileDataSource;
052import jakarta.mail.Message;
053import jakarta.mail.MessagingException;
054import jakarta.mail.Multipart;
055import jakarta.mail.Session;
056import jakarta.mail.internet.InternetAddress;
057import jakarta.mail.internet.MimeBodyPart;
058import jakarta.mail.internet.MimeMessage;
059
060import demo.DemoSMimeUtil;
061import demo.DemoUtil;
062import demo.keystore.CMSKeyStore;
063import demo.smime.DumpMessage;
064
065/**
066 * This class shows how to create, sign and then parse/verify a 
067 * mulitpart/signed message where the content is not canonicalized.
068 * <p>
069 * The only difference to the common usage of this S/MIME library
070 * is to use a {@link iaik.smime.BinaryCanonicalizer binary
071 * canonicalizer} which does not canonicalize the content.  
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 * @see iaik.smime.SignedContent
090 * @see iaik.smime.BinaryCanonicalizer
091 */
092public class BinarySignedDemo {
093    
094  // whether to print dump all generates test messages to System.out
095  final static boolean PRINT_MESSAGES = false;   
096
097  String firstName_ = "John";                     // name of sender
098  String lastName_ = "SMime";
099  String from_ = "smimetest@iaik.tugraz.at";      // email sender
100  String to_ = "smimetest@iaik.tugraz.at";        // email recipient
101  String host_ = "mailhost";                      // name of the mailhost
102
103  X509Certificate[] signerCertificates_;          // list of certificates to include in the S/MIME message
104  X509Certificate recipientCertificate_;          // certificate of the recipient
105  X509Certificate signerCertificate_;             // certificate of the signer/sender
106  X509Certificate encryptionCertOfSigner_;        // signer uses different certificate for encryption
107  PrivateKey signerPrivateKey_;                   // private key of the signer/sender
108  
109  /**
110   * Default constructor. Reads certificates and keys from the demo keystore.
111   */
112  public BinarySignedDemo() {
113    
114    System.out.println();
115    System.out.println("********************************************************************************************");
116    System.out.println("*                                 BinarySignedDemo                                         *");
117    System.out.println("* (shows how to sign and verify multipart/signed S/MIME messages without canonicalization) *");
118    System.out.println("********************************************************************************************");
119    System.out.println();
120    
121    // get the certificates from the KeyStore
122    signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
123    signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
124    signerCertificate_ = signerCertificates_[0];
125
126    // recipient = signer for this test
127    recipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
128    encryptionCertOfSigner_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
129  }
130  
131  /**
132   * Starts the demo.
133   *
134   * @throws IOException if an I/O related error occurs
135   */
136  public void start() throws IOException {
137
138        // get the default Session
139        Session session = DemoSMimeUtil.getSession();
140    
141
142        try {
143      
144      // we use a binary canonicalizer
145      SMimeParameters.setCanonicalizer(new BinaryCanonicalizer());
146      // Create a demo Multipart
147      MimeBodyPart mbp1 = new SMimeBodyPart();
148      mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
149          // attachment
150      MimeBodyPart attachment = new SMimeBodyPart();
151      attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
152      attachment.setFileName("test.html");
153        
154      Multipart mp = new SMimeMultipart();
155      mp.addBodyPart(mbp1);
156      mp.addBodyPart(attachment);
157      DataHandler multipart = new DataHandler(mp, mp.getContentType());
158
159      Message msg;    // the message to send
160      ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
161      ByteArrayInputStream bais;  // we read from a stream
162
163     
164
165      // create explicitly signed message
166      msg = createSignedMessage(session, multipart);
167      System.out.println("creating explicitly signed message...");
168      baos.reset();
169          msg.saveChanges();
170          msg.writeTo(baos);
171          bais = new ByteArrayInputStream(baos.toByteArray());
172          msg = new MimeMessage(session, bais);
173          if (PRINT_MESSAGES) {
174        printMessage(msg);
175      }
176      DumpMessage.dumpMsg(msg);
177   
178        } catch (Exception ex) {
179      ex.printStackTrace();
180          throw new RuntimeException(ex.toString());
181        } finally {
182      // reset to default canonicalizer
183      SMimeParameters.setCanonicalizer(new DefaultCanonicalizer()); 
184    }
185
186  }
187  
188  /**
189   * Creates a signed message.
190   *
191   * @param session the mail session
192   * @param dataHandler the content of the message to be signed
193   * 
194   * @return the signed message
195   *
196   * @throws MessagingException if an error occurs when creating the message
197   */
198  public Message createSignedMessage(Session session, DataHandler dataHandler)
199    throws MessagingException {
200
201    String subject = "IAIK-S/MIME: Explicitly Signed";
202    
203    MimeMessage msg = new MimeMessage(session);
204    msg.setFrom(new InternetAddress(from_));
205    msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to_, false));
206    msg.setSentDate(new Date());
207    msg.setSubject(subject);
208
209    SignedContent sc = new SignedContent(false);
210
211    // set content
212    sc.setDataHandler(dataHandler);
213    sc.setCertificates(signerCertificates_);
214
215    try {
216      sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_);
217    } catch (NoSuchAlgorithmException ex) {
218      throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
219    }
220
221    msg.setContent(sc, sc.getContentType());
222    // let the SignedContent update some message headers
223    sc.setHeaders(msg);
224    return msg;
225  }
226  
227  
228  /** 
229   * Prints a dump of the given message to System.out.
230   *
231   * @param msg the message to be dumped to System.out
232   */
233  private static void printMessage(Message msg) throws IOException {
234    System.out.println("------------------------------------------------------------------");
235    System.out.println("Message dump: \n");
236    try {
237      msg.writeTo(System.out);
238    } catch (MessagingException ex) {
239      throw new IOException(ex.getMessage());   
240    }    
241    System.out.println("\n------------------------------------------------------------------");
242  }  
243
244
245  /**
246   * The main method.
247   */
248  public static void main(String[] argv) throws IOException {
249
250    DemoSMimeUtil.initDemos();
251        (new BinarySignedDemo()).start();
252    System.out.println("\nReady!");
253    DemoUtil.waitKey();
254  }
255}