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/SMimeV3SHA2withDSADemo.java 10    12.02.25 17:58 Dbratko $
059    // $Revision: 10 $
060    //
061    
062    package demo.smime.basic;
063    
064    import iaik.asn1.structures.AlgorithmID;
065    import iaik.cms.CMSAlgorithmID;
066    import iaik.smime.SMimeBodyPart;
067    import iaik.smime.SMimeMultipart;
068    import iaik.smime.SignedContent;
069    import iaik.x509.X509Certificate;
070    
071    import java.io.ByteArrayInputStream;
072    import java.io.ByteArrayOutputStream;
073    import java.io.IOException;
074    import java.security.NoSuchAlgorithmException;
075    import java.security.PrivateKey;
076    import java.util.Date;
077    
078    import javax.activation.DataHandler;
079    import javax.activation.FileDataSource;
080    import javax.mail.Message;
081    import javax.mail.MessagingException;
082    import javax.mail.Multipart;
083    import javax.mail.Session;
084    import javax.mail.internet.InternetAddress;
085    import javax.mail.internet.MimeBodyPart;
086    import javax.mail.internet.MimeMessage;
087    
088    import demo.DemoSMimeUtil;
089    import demo.DemoUtil;
090    import demo.keystore.CMSKeyStore;
091    import demo.smime.DumpMessage;
092    
093    /**
094     * This class demonstrates the usage of the IAIK S/MIME implementation with the 
095     * SHA2withDSA signature algorithm (FIPS 186-3). It shows how to create signed
096     * S/MIMEv3 messages and how to parse them and verify the signature.
097     * <p>
098     * To run this demo the following packages are required:
099     * <ul>
100     *    <li>
101     *       <code>iaik_cms.jar</code> (IAIK-CMS/SMIME)
102     *    </li>
103     *    <li>
104     *       <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>).
105     *    </li>
106     *    <li>
107     *       <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
108     *    </li>   
109     *    <li>
110     *       <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).
111     *    </li> 
112     * </ul>
113     */
114    public class SMimeV3SHA2withDSADemo {
115      
116    //whether to print dump all generates test messages to System.out
117      final static boolean PRINT_MESSAGES = false;   
118      
119    
120      String firstName = "John";
121      String lastName = "SMime";
122      String to = "smimetest@iaik.tugraz.at";     // email recipient
123      String from = "smimetest@iaik.tugraz.at";   // email sender
124      String host = "mailhost";                       // name of the mailhost
125    
126      X509Certificate[] signerCertificates;          // list of certificates to include in the S/MIME message
127      X509Certificate signerCertificate;             // certificate of the signer/sender
128      PrivateKey signerPrivateKey;                   // private key of the signer/sender
129        
130      /**
131       * Default constructor. Reads certificates and keys from the demo keystore.
132       */
133      public SMimeV3SHA2withDSADemo() {
134        //  get the certificates from the KeyStore
135        signerCertificates = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_3072_SIGN);
136        signerPrivateKey = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_3072_SIGN);
137        signerCertificate = signerCertificates[0];
138      }
139      
140      /**
141       * Starts the demo.
142       *
143       * @throws IOException if an I/O related error occurs
144       */
145      public void start() throws IOException {
146    
147        // get the default Session
148            Session session = DemoSMimeUtil.getSession();
149    
150            try {
151          // Create a demo Multipart
152          MimeBodyPart mbp1 = new SMimeBodyPart();
153              mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
154              // attachment
155          MimeBodyPart attachment = new SMimeBodyPart();
156          attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
157          attachment.setFileName("test.html");
158    
159          Multipart mp = new SMimeMultipart();
160          mp.addBodyPart(mbp1);
161          mp.addBodyPart(attachment);
162          DataHandler multipart = new DataHandler(mp, mp.getContentType());
163    
164          Message msg;    // the message to send
165          ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
166          ByteArrayInputStream bais;  // we read from a stream
167          
168          AlgorithmID digestAlgorithm = CMSAlgorithmID.sha256;
169          AlgorithmID signatureAlgorithm = CMSAlgorithmID.dsaWithSHA256;
170    
171          //    1. This is an explicitly signed message
172          msg = createSignedMessage(session, 
173                                    multipart, 
174                                    false,
175                                    (AlgorithmID)digestAlgorithm.clone(),
176                                    (AlgorithmID)signatureAlgorithm.clone());
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          // 2. This is an implicitly signed message
192          msg = createSignedMessage(session, 
193                                    multipart,
194                                    true, 
195                                    (AlgorithmID)digestAlgorithm.clone(),
196                                    (AlgorithmID)signatureAlgorithm.clone());
197          System.out.println("creating implicitly 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          System.out.println("\n\n*****************************************\n\n");
209    
210            } catch (Exception ex) {
211          ex.printStackTrace();
212              throw new RuntimeException(ex.toString());
213            }
214      }
215      
216      /**
217       * Creates a signed message.
218       *
219       * @param session the mail session
220       * @param dataHandler the content of the message to be signed
221       * @param implicit whether to use implicit (application/pkcs7-mime) or explicit
222       *                 (multipart/signed) signing
223       * @param digestAlgorithm the digest algorithm to be used
224       * @param signatureAlgorithm the signature algorithm to be used                
225       * 
226       * @return the signed message
227       *
228       * @throws MessagingException if an error occurs when creating the message
229       */
230      public Message createSignedMessage(Session session, 
231                                         DataHandler dataHandler,
232                                         boolean implicit,
233                                         AlgorithmID digestAlgorithm,
234                                         AlgorithmID signatureAlgorithm)
235          throws MessagingException {
236    
237        String subject = null;
238        StringBuffer buf = new StringBuffer();
239        
240        if (implicit) {
241          subject = "IAIK-S/MIME: Implicitly Signed";
242          buf.append("This message is implicitly signed!\n");
243          buf.append("You need an S/MIME aware mail client to view this message.\n");
244          buf.append("\n\n");
245        } else {
246          subject = "IAIK-S/MIME: Explicitly Signed";
247          buf.append("This message is explicitly signed!\n");
248          buf.append("Every mail client can view this message.\n");
249          buf.append("Non S/MIME mail clients will show the signature as attachment.\n");
250          buf.append("\n\n");
251        }
252        
253        Message msg = createMessage(session, subject);
254        
255        SignedContent sc = new SignedContent(implicit);
256        if (dataHandler != null) {
257          sc.setDataHandler(dataHandler);
258        } else {
259          sc.setText(buf.toString());
260        }
261        sc.setCertificates(signerCertificates);
262    
263        try {
264          sc.addSigner(signerPrivateKey, 
265                       signerCertificate,
266                       (AlgorithmID)digestAlgorithm.clone(),
267                       (AlgorithmID)signatureAlgorithm.clone());
268        } catch (NoSuchAlgorithmException ex) {
269          throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
270        }
271    
272        msg.setContent(sc, sc.getContentType());
273        // let the SignedContent update some message headers
274        sc.setHeaders(msg);
275        return msg;
276      }
277      
278      /**
279       * Creates a MIME message container with the given subject for the given session.
280       * 
281       * @param session the mail sesion
282       * @param subject the subject of the message
283       *
284       * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
285       *
286       * @throws MessagingException if the message cannot be created
287       */
288      public Message createMessage(Session session, String subject) throws MessagingException {
289        MimeMessage msg = new MimeMessage(session);
290        msg.setFrom(new InternetAddress(from));
291        msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));
292        msg.setSentDate(new Date());
293        msg.setSubject(subject);
294        return msg;
295      }
296      
297      /** 
298       * Prints a dump of the given message to System.out.
299       *
300       * @param msg the message to be dumped to System.out
301       *
302       * @throws IOException if an I/O error occurs
303       */
304      static void printMessage(Message msg) throws IOException {
305        System.out.println("------------------------------------------------------------------");
306        System.out.println("Message dump: \n");
307        try {
308          msg.writeTo(System.out);
309        } catch (MessagingException ex) {
310          throw new IOException(ex.getMessage());   
311        }    
312        System.out.println("\n------------------------------------------------------------------");
313      } 
314    
315    
316      /**
317       * The main method.
318       */
319      public static void main(String[] argv) throws IOException {
320        double iaikProviderVersion = DemoUtil.getIaikProviderVersion(); 
321        if (iaikProviderVersion <= 3.18) {
322          System.err.println("This demo requires a IAIK provider version > 3.18! Your IAIK provider version is " + iaikProviderVersion + ".");
323        } else {
324          DemoSMimeUtil.initDemos();
325              (new SMimeV3SHA2withDSADemo()).start();
326          System.out.println("\nReady!");
327        }  
328        DemoUtil.waitKey();
329      }
330    }