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/SMimeShowDemo.java 30 12.02.25 17:58 Dbratko $
059 // $Revision: 30 $
060 //
061
062 package demo.smime.basic;
063
064 import iaik.smime.TrustVerifier;
065 import iaik.x509.X509Certificate;
066
067 import java.io.IOException;
068 import java.security.cert.CertificateException;
069 import java.util.Date;
070
071 import javax.mail.Address;
072 import javax.mail.FetchProfile;
073 import javax.mail.Flags;
074 import javax.mail.Folder;
075 import javax.mail.Message;
076 import javax.mail.MessagingException;
077 import javax.mail.Session;
078 import javax.mail.Store;
079 import javax.mail.URLName;
080
081 import demo.DemoSMimeUtil;
082 import demo.DemoUtil;
083 import demo.cms.ecc.ECCDemoUtil;
084 import demo.keystore.CMSKeyStore;
085 import demo.smime.DumpMessage;
086
087 /**
088 * This class demonstrates the usage of the IAIK S/MIME implementation for downloading
089 * and verifying/decrypting signed and/or encrypted emails from some mail server.
090 * <p>
091 * To run this demo the following packages are required:
092 * <ul>
093 * <li>
094 * <code>iaik_cms.jar</code> (IAIK-CMS/SMIME)
095 * </li>
096 * <li>
097 * <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>).
098 * </li>
099 * <li>
100 * <code>iaik_eccelerate.jar</code> (<a href="https://sic.tech/products/core-crypto-toolkits/eccelerate/" target="_blank">IAIK ECC Library</a>, if you want to use Elliptic Curve Cryptography).
101 * </li>
102 * <li>
103 * <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
104 * </li>
105 * <li>
106 * <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).
107 * </li>
108 * </ul>
109 *
110 * <b>Usage:</b>
111 * <pre>
112 * SMimeShow [-L url] [-T protocol] [-H host] [-U user] [-P password] [-f mailbox] [msgnum] [-v]
113 * </pre>
114 * <b>Example</b> to display message 2:
115 * <pre>
116 * SMimeShow -T imap -H mailhost -U test -P test -f INBOX 2
117 * </pre>
118 *
119 * @see iaik.smime.EncryptedContent
120 * @see iaik.smime.SignedContent
121 */
122 public class SMimeShowDemo {
123
124 String from;
125 String protocol;
126 String host = null;
127 String user = null;
128 String password = null;
129 String mbox = "INBOX";
130 String url = null;
131 boolean verbose = false;
132
133 /**
134 * Simple trust verifier.
135 */
136 private static TrustVerifier trustVerifier_ = null;
137
138
139
140 /**
141 * Default constructor. Reads certificates and keys from the demo keystore.
142 */
143 public SMimeShowDemo() {
144
145 System.out.println();
146 System.out.println("******************************************************************************************");
147 System.out.println("* SMimeShow demo *");
148 System.out.println("* (shows how to parse and verify/decrypt signed and/or encrypted S/MIME messages) *");
149 System.out.println("******************************************************************************************");
150 System.out.println();
151
152
153 trustVerifier_ = new TrustVerifier();
154 // set demo CAs as trusted
155 trustVerifier_.addTrustedCertificate(CMSKeyStore.getCaCertificate(CMSKeyStore.RSA));
156 trustVerifier_.addTrustedCertificate(CMSKeyStore.getCaCertificate(CMSKeyStore.DSA));
157 trustVerifier_.addTrustedCertificate(CMSKeyStore.getCaCertificate(CMSKeyStore.RSAPSS));
158
159 // if EC is available set EC demo CAs as trusted, too
160 try {
161 trustVerifier_.addTrustedCertificate(demo.cms.ecc.keystore.CMSEccKeyStore.getCaCertificate());
162 } catch (Exception e) {
163 System.err.println("Cannot add EC demo CAs (EC not available?): " + e.toString());
164 }
165 }
166
167 /**
168 * Connects to the mail server, downloads messages, verifies/decrypts
169 * them (if they are signed/encrypted).
170 *
171 * @param argv optional parameters like mailhost, account name,...
172 *
173 * @throws IOException if an I/O related error occurs
174 */
175 public void show(String[] argv) throws IOException {
176
177 int msgnum = -1;
178 int optind = 0;
179
180 // some defaults
181 protocol = "pop3";
182 host = "mailhost";
183 verbose = true;
184
185 if (argv.length > 0) {
186 for (optind = 0; optind < argv.length; optind++) {
187 if (argv[optind].equals("-T")) {
188 protocol = argv[++optind];
189 } else if (argv[optind].equals("-H")) {
190 host = argv[++optind];
191 } else if (argv[optind].equals("-U")) {
192 user = argv[++optind];
193 } else if (argv[optind].equals("-P")) {
194 password = argv[++optind];
195 } else if (argv[optind].equals("-v")) {
196 verbose = true;
197 } else if (argv[optind].equals("-f")) {
198 mbox = argv[++optind];
199 } else if (argv[optind].equals("-L")) {
200 url = argv[++optind];
201 } else if (argv[optind].equals("--")) {
202 optind++;
203 break;
204 } else if (argv[optind].startsWith("-")) {
205 System.out.println("Usage: SMimeShow [-L url] [-T protocol] [-H host] [-U user] [-P password] [-f mailbox] [msgnum] [-v]");
206 System.exit(1);
207 } else {
208 break;
209 }
210 }
211 }
212
213 try {
214 if (optind < argv.length)
215 msgnum = Integer.parseInt(argv[optind]);
216
217 // get the default Session
218 Session session = DemoSMimeUtil.getSession();
219
220 // Get a Store object
221 Store store = null;
222 if (url != null) {
223 URLName urln = new URLName(url);
224 store = session.getStore(urln);
225 store.connect();
226 } else {
227 if (protocol != null) {
228 store = session.getStore(protocol);
229 } else {
230 store = session.getStore();
231 }
232 // Connect
233 if (host != null || user != null || password != null) {
234 store.connect(host, user, password);
235 } else {
236 store.connect();
237 }
238 }
239
240 // Open the Folder
241 Folder folder = store.getDefaultFolder();
242 if (folder == null) {
243 System.out.println("No default folder");
244 System.exit(1);
245 }
246
247 folder = folder.getFolder(mbox);
248 if (folder == null) {
249 System.out.println("Invalid folder");
250 System.exit(1);
251 }
252
253 // folder.open(Folder.READ_WRITE);
254 folder.open(Folder.READ_ONLY); // only READ for POP3
255 int totalMessages = folder.getMessageCount();
256
257 if (totalMessages == 0) {
258 System.out.println("Empty folder");
259 folder.close(false);
260 store.close();
261 System.exit(1);
262 }
263
264 if (verbose) {
265 int newMessages = folder.getNewMessageCount();
266 System.out.println("Total messages = " + totalMessages);
267 System.out.println("New messages = " + newMessages);
268 System.out.println("-------------------------------");
269 }
270
271 if (msgnum == -1) {
272 // Attributes & Flags for all messages ..
273 Message[] msgs = folder.getMessages();
274
275 // Use a suitable FetchProfile
276 FetchProfile fp = new FetchProfile();
277 fp.add(FetchProfile.Item.ENVELOPE);
278 fp.add(FetchProfile.Item.FLAGS);
279 fp.add("X-Mailer");
280 folder.fetch(msgs, fp);
281
282 for (int i = 0; i < msgs.length; i++) {
283
284 System.out.println("--------------------------");
285 System.out.println("MESSAGE #" + (i + 1) + ":");
286 from = msgs[i].getFrom()[0].toString();
287 dump(msgs[i]);
288 }
289 } else {
290 System.out.println("Getting message number: " + msgnum);
291 Message m = folder.getMessage(msgnum);
292 from = m.getFrom()[0].toString();
293 dump(m);
294 }
295
296 folder.close(false);
297 store.close();
298
299 // System.in.read();
300 } catch (Exception ex) {
301 ex.printStackTrace();
302 throw new RuntimeException(ex.toString());
303 }
304
305 }
306
307 /**
308 * Dumps the given object (message).
309 *
310 * @param o the object (message) to be dumped
311 *
312 * @throws Exception if some error occurs
313 */
314 public void dump(Object o) throws Exception {
315 DumpMessage dumpMsg = new DumpMessage();
316 dumpMsg.dump(o);
317
318 // message signed and signer certs included?
319 X509Certificate[] signerCerts = dumpMsg.getSignerCerts();
320 if (signerCerts != null) {
321 try {
322 trustVerifier_.verifyCertificateChain(signerCerts);
323 System.out.println("Certificate chain trusted!");
324 } catch (CertificateException ex) {
325 System.out.println("Certificate chain not trusted!");
326 }
327 // is email in cert equal to email from From: header?
328 // the email has to be formatted as an "addr-spec" as defined in RFC 822.
329 // An addr-spec has the form "local-part@domain".
330 if (trustVerifier_.checkEMail(from, signerCerts[0])) {
331 System.out.println("EMail is ok!");
332 } else {
333 System.out.println("EMail not ok!");
334 }
335 }
336 }
337
338 /**
339 * Prints the envelope of a message.
340 *
341 * @param m the message
342 *
343 * @throws MessagingException if an error occurs
344 */
345 public static void dumpEnvelope(Message m) throws MessagingException {
346 System.out.println("This is the message envelope");
347 System.out.println("---------------------------");
348 Address[] a;
349 // FROM
350 if ((a = m.getFrom()) != null) {
351 for (int j = 0; j < a.length; j++)
352 System.out.println("FROM: " + a[j].toString());
353 }
354
355 // TO
356 if ((a = m.getRecipients(Message.RecipientType.TO)) != null) {
357 for (int j = 0; j < a.length; j++)
358 System.out.println("TO: " + a[j].toString());
359 }
360
361 // SUBJECT
362 System.out.println("SUBJECT: " + m.getSubject());
363
364 // DATE
365 Date d = m.getSentDate();
366 System.out.println("SendDate: "+(d != null ? d.toString() : "UNKNOWN"));
367
368 // SIZE
369 System.out.println("Size: " + m.getSize());
370
371 // FLAGS:
372 Flags flags = m.getFlags();
373 StringBuffer sb = new StringBuffer();
374 Flags.Flag[] sf = flags.getSystemFlags(); // get the system flags
375
376 boolean first = true;
377 for (int i = 0; i < sf.length; i++) {
378 String s;
379 Flags.Flag f = sf[i];
380 if (f == Flags.Flag.ANSWERED)
381 s = "\\Answered";
382 else if (f == Flags.Flag.DELETED)
383 s = "\\Deleted";
384 else if (f == Flags.Flag.DRAFT)
385 s = "\\Draft";
386 else if (f == Flags.Flag.FLAGGED)
387 s = "\\Flagged";
388 else if (f == Flags.Flag.RECENT)
389 s = "\\Recent";
390 else if (f == Flags.Flag.SEEN)
391 s = "\\Seen";
392 else
393 continue; // skip it
394 if (first)
395 first = false;
396 else
397 sb.append(' ');
398 sb.append(s);
399 }
400
401 String[] uf = flags.getUserFlags(); // get the user flag strings
402 for (int i = 0; i < uf.length; i++) {
403 if (first)
404 first = false;
405 else
406 sb.append(' ');
407 sb.append(uf[i]);
408 }
409 System.out.println("FLAGS = " + sb.toString());
410
411 // X-MAILER
412 String[] hdrs = m.getHeader("X-Mailer");
413 if (hdrs != null)
414 System.out.println("X-Mailer: " + hdrs[0]);
415 else
416 System.out.println("X-Mailer NOT available");
417 }
418
419 /**
420 * Main method.
421 */
422 public static void main(String argv[]) throws Exception {
423 DemoSMimeUtil.initDemos();
424 // add ECC provider
425 ECCDemoUtil.installIaikEccProvider();
426 (new SMimeShowDemo()).show(argv);
427 System.out.println("\nReady!");
428 DemoUtil.waitKey();
429 }
430 }