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 }