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