001// Copyright (C) 2002 IAIK 002// https://sic.tech/ 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// This source is provided for inspection purposes and recompilation only, 011// unless specified differently in a contract with IAIK. This source has to 012// be kept in strict confidence and must not be disclosed to any third party 013// under any circumstances. Redistribution in source and binary forms, with 014// or without modification, are <not> permitted in any case! 015// 016// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 017// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 018// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 019// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 020// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 021// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 022// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 023// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 024// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 025// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 026// SUCH DAMAGE. 027// 028// $Header: /IAIK-CMS/current/src/demo/smime/basic/SMimeV3SHA2withDSADemo.java 10 12.02.25 17:58 Dbratko $ 029// $Revision: 10 $ 030// 031 032package demo.smime.basic; 033 034import iaik.asn1.structures.AlgorithmID; 035import iaik.cms.CMSAlgorithmID; 036import iaik.smime.SMimeBodyPart; 037import iaik.smime.SMimeMultipart; 038import iaik.smime.SignedContent; 039import iaik.x509.X509Certificate; 040 041import java.io.ByteArrayInputStream; 042import java.io.ByteArrayOutputStream; 043import java.io.IOException; 044import java.security.NoSuchAlgorithmException; 045import java.security.PrivateKey; 046import java.util.Date; 047 048import jakarta.activation.DataHandler; 049import jakarta.activation.FileDataSource; 050import jakarta.mail.Message; 051import jakarta.mail.MessagingException; 052import jakarta.mail.Multipart; 053import jakarta.mail.Session; 054import jakarta.mail.internet.InternetAddress; 055import jakarta.mail.internet.MimeBodyPart; 056import jakarta.mail.internet.MimeMessage; 057 058import demo.DemoSMimeUtil; 059import demo.DemoUtil; 060import demo.keystore.CMSKeyStore; 061import demo.smime.DumpMessage; 062 063/** 064 * This class demonstrates the usage of the IAIK S/MIME implementation with the 065 * SHA2withDSA signature algorithm (FIPS 186-3). It shows how to create signed 066 * S/MIMEv3 messages and how to parse them and verify the signature. 067 * <p> 068 * To run this demo the following packages are required: 069 * <ul> 070 * <li> 071 * <code>iaik_cms.jar</code> (IAIK-CMS/SMIME) 072 * </li> 073 * <li> 074 * <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>). 075 * </li> 076 * <li> 077 * <a href="https://jakarta.ee/specifications/mail/" target="_blank">Jakarta</a>/<a href="https://eclipse-ee4j.github.io/angus-mail/" target="_blank">Angus</a> Mail 078 * </li> 079 * <li> 080 * <a href="https://jakarta.ee/specifications/activation/" target="_blank">Jakarta Activation Framework</a> 081 * </li> 082 * </ul> 083 */ 084public class SMimeV3SHA2withDSADemo { 085 086//whether to print dump all generates test messages to System.out 087 final static boolean PRINT_MESSAGES = false; 088 089 090 String firstName = "John"; 091 String lastName = "SMime"; 092 String to = "smimetest@iaik.tugraz.at"; // email recipient 093 String from = "smimetest@iaik.tugraz.at"; // email sender 094 String host = "mailhost"; // name of the mailhost 095 096 X509Certificate[] signerCertificates; // list of certificates to include in the S/MIME message 097 X509Certificate signerCertificate; // certificate of the signer/sender 098 PrivateKey signerPrivateKey; // private key of the signer/sender 099 100 /** 101 * Default constructor. Reads certificates and keys from the demo keystore. 102 */ 103 public SMimeV3SHA2withDSADemo() { 104 // get the certificates from the KeyStore 105 signerCertificates = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_3072_SIGN); 106 signerPrivateKey = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_3072_SIGN); 107 signerCertificate = signerCertificates[0]; 108 } 109 110 /** 111 * Starts the demo. 112 * 113 * @throws IOException if an I/O related error occurs 114 */ 115 public void start() throws IOException { 116 117 // get the default Session 118 Session session = DemoSMimeUtil.getSession(); 119 120 try { 121 // Create a demo Multipart 122 MimeBodyPart mbp1 = new SMimeBodyPart(); 123 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n"); 124 // attachment 125 MimeBodyPart attachment = new SMimeBodyPart(); 126 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html"))); 127 attachment.setFileName("test.html"); 128 129 Multipart mp = new SMimeMultipart(); 130 mp.addBodyPart(mbp1); 131 mp.addBodyPart(attachment); 132 DataHandler multipart = new DataHandler(mp, mp.getContentType()); 133 134 Message msg; // the message to send 135 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream 136 ByteArrayInputStream bais; // we read from a stream 137 138 AlgorithmID digestAlgorithm = CMSAlgorithmID.sha256; 139 AlgorithmID signatureAlgorithm = CMSAlgorithmID.dsaWithSHA256; 140 141 // 1. This is an explicitly signed message 142 msg = createSignedMessage(session, 143 multipart, 144 false, 145 (AlgorithmID)digestAlgorithm.clone(), 146 (AlgorithmID)signatureAlgorithm.clone()); 147 System.out.println("creating explicitly signed message..."); 148 baos.reset(); 149 msg.saveChanges(); 150 msg.writeTo(baos); 151 bais = new ByteArrayInputStream(baos.toByteArray()); 152 msg = new MimeMessage(session, bais); 153 if (PRINT_MESSAGES) { 154 printMessage(msg); 155 } 156 DumpMessage.dumpMsg(msg); 157 158 System.out.println("\n\n*****************************************\n\n"); 159 160 161 // 2. This is an implicitly signed message 162 msg = createSignedMessage(session, 163 multipart, 164 true, 165 (AlgorithmID)digestAlgorithm.clone(), 166 (AlgorithmID)signatureAlgorithm.clone()); 167 System.out.println("creating implicitly signed message..."); 168 baos.reset(); 169 msg.saveChanges(); 170 msg.writeTo(baos); 171 bais = new ByteArrayInputStream(baos.toByteArray()); 172 msg = new MimeMessage(session, bais); 173 if (PRINT_MESSAGES) { 174 printMessage(msg); 175 } 176 DumpMessage.dumpMsg(msg); 177 178 System.out.println("\n\n*****************************************\n\n"); 179 180 } catch (Exception ex) { 181 ex.printStackTrace(); 182 throw new RuntimeException(ex.toString()); 183 } 184 } 185 186 /** 187 * Creates a signed message. 188 * 189 * @param session the mail session 190 * @param dataHandler the content of the message to be signed 191 * @param implicit whether to use implicit (application/pkcs7-mime) or explicit 192 * (multipart/signed) signing 193 * @param digestAlgorithm the digest algorithm to be used 194 * @param signatureAlgorithm the signature algorithm to be used 195 * 196 * @return the signed message 197 * 198 * @throws MessagingException if an error occurs when creating the message 199 */ 200 public Message createSignedMessage(Session session, 201 DataHandler dataHandler, 202 boolean implicit, 203 AlgorithmID digestAlgorithm, 204 AlgorithmID signatureAlgorithm) 205 throws MessagingException { 206 207 String subject = null; 208 StringBuffer buf = new StringBuffer(); 209 210 if (implicit) { 211 subject = "IAIK-S/MIME: Implicitly Signed"; 212 buf.append("This message is implicitly signed!\n"); 213 buf.append("You need an S/MIME aware mail client to view this message.\n"); 214 buf.append("\n\n"); 215 } else { 216 subject = "IAIK-S/MIME: Explicitly Signed"; 217 buf.append("This message is explicitly signed!\n"); 218 buf.append("Every mail client can view this message.\n"); 219 buf.append("Non S/MIME mail clients will show the signature as attachment.\n"); 220 buf.append("\n\n"); 221 } 222 223 Message msg = createMessage(session, subject); 224 225 SignedContent sc = new SignedContent(implicit); 226 if (dataHandler != null) { 227 sc.setDataHandler(dataHandler); 228 } else { 229 sc.setText(buf.toString()); 230 } 231 sc.setCertificates(signerCertificates); 232 233 try { 234 sc.addSigner(signerPrivateKey, 235 signerCertificate, 236 (AlgorithmID)digestAlgorithm.clone(), 237 (AlgorithmID)signatureAlgorithm.clone()); 238 } catch (NoSuchAlgorithmException ex) { 239 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 240 } 241 242 msg.setContent(sc, sc.getContentType()); 243 // let the SignedContent update some message headers 244 sc.setHeaders(msg); 245 return msg; 246 } 247 248 /** 249 * Creates a MIME message container with the given subject for the given session. 250 * 251 * @param session the mail sesion 252 * @param subject the subject of the message 253 * 254 * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content) 255 * 256 * @throws MessagingException if the message cannot be created 257 */ 258 public Message createMessage(Session session, String subject) throws MessagingException { 259 MimeMessage msg = new MimeMessage(session); 260 msg.setFrom(new InternetAddress(from)); 261 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false)); 262 msg.setSentDate(new Date()); 263 msg.setSubject(subject); 264 return msg; 265 } 266 267 /** 268 * Prints a dump of the given message to System.out. 269 * 270 * @param msg the message to be dumped to System.out 271 * 272 * @throws IOException if an I/O error occurs 273 */ 274 static void printMessage(Message msg) throws IOException { 275 System.out.println("------------------------------------------------------------------"); 276 System.out.println("Message dump: \n"); 277 try { 278 msg.writeTo(System.out); 279 } catch (MessagingException ex) { 280 throw new IOException(ex.getMessage()); 281 } 282 System.out.println("\n------------------------------------------------------------------"); 283 } 284 285 286 /** 287 * The main method. 288 */ 289 public static void main(String[] argv) throws IOException { 290 double iaikProviderVersion = DemoUtil.getIaikProviderVersion(); 291 if (iaikProviderVersion <= 3.18) { 292 System.err.println("This demo requires a IAIK provider version > 3.18! Your IAIK provider version is " + iaikProviderVersion + "."); 293 } else { 294 DemoSMimeUtil.initDemos(); 295 (new SMimeV3SHA2withDSADemo()).start(); 296 System.out.println("\nReady!"); 297 } 298 DemoUtil.waitKey(); 299 } 300}