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 < 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 }