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/BinarySignedDemo.java 22 12.02.25 17:58 Dbratko $
059 // $Revision: 22 $
060 //
061
062 package demo.smime.basic;
063
064 import iaik.smime.BinaryCanonicalizer;
065 import iaik.smime.DefaultCanonicalizer;
066 import iaik.smime.SMimeBodyPart;
067 import iaik.smime.SMimeMultipart;
068 import iaik.smime.SMimeParameters;
069 import iaik.smime.SignedContent;
070 import iaik.x509.X509Certificate;
071
072 import java.io.ByteArrayInputStream;
073 import java.io.ByteArrayOutputStream;
074 import java.io.IOException;
075 import java.security.NoSuchAlgorithmException;
076 import java.security.PrivateKey;
077 import java.security.interfaces.RSAPrivateKey;
078 import java.util.Date;
079
080 import javax.activation.DataHandler;
081 import javax.activation.FileDataSource;
082 import javax.mail.Message;
083 import javax.mail.MessagingException;
084 import javax.mail.Multipart;
085 import javax.mail.Session;
086 import javax.mail.internet.InternetAddress;
087 import javax.mail.internet.MimeBodyPart;
088 import javax.mail.internet.MimeMessage;
089
090 import demo.DemoSMimeUtil;
091 import demo.DemoUtil;
092 import demo.keystore.CMSKeyStore;
093 import demo.smime.DumpMessage;
094
095 /**
096 * This class shows how to create, sign and then parse/verify a
097 * mulitpart/signed message where the content is not canonicalized.
098 * <p>
099 * The only difference to the common usage of this S/MIME library
100 * is to use a {@link iaik.smime.BinaryCanonicalizer binary
101 * canonicalizer} which does not canonicalize the content.
102 * <p>
103 * To run this demo the following packages are required:
104 * <ul>
105 * <li>
106 * <code>iaik_cms.jar</code> (IAIK-CMS/SMIME)
107 * </li>
108 * <li>
109 * <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>).
110 * </li>
111 * <li>
112 * <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
113 * </li>
114 * <li>
115 * <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).
116 * </li>
117 * </ul>
118 *
119 * @see iaik.smime.SignedContent
120 * @see iaik.smime.BinaryCanonicalizer
121 */
122 public class BinarySignedDemo {
123
124 // whether to print dump all generates test messages to System.out
125 final static boolean PRINT_MESSAGES = false;
126
127 String firstName_ = "John"; // name of sender
128 String lastName_ = "SMime";
129 String from_ = "smimetest@iaik.tugraz.at"; // email sender
130 String to_ = "smimetest@iaik.tugraz.at"; // email recipient
131 String host_ = "mailhost"; // name of the mailhost
132
133 X509Certificate[] signerCertificates_; // list of certificates to include in the S/MIME message
134 X509Certificate recipientCertificate_; // certificate of the recipient
135 X509Certificate signerCertificate_; // certificate of the signer/sender
136 X509Certificate encryptionCertOfSigner_; // signer uses different certificate for encryption
137 PrivateKey signerPrivateKey_; // private key of the signer/sender
138
139 /**
140 * Default constructor. Reads certificates and keys from the demo keystore.
141 */
142 public BinarySignedDemo() {
143
144 System.out.println();
145 System.out.println("********************************************************************************************");
146 System.out.println("* BinarySignedDemo *");
147 System.out.println("* (shows how to sign and verify multipart/signed S/MIME messages without canonicalization) *");
148 System.out.println("********************************************************************************************");
149 System.out.println();
150
151 // get the certificates from the KeyStore
152 signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
153 signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
154 signerCertificate_ = signerCertificates_[0];
155
156 // recipient = signer for this test
157 recipientCertificate_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0];
158 encryptionCertOfSigner_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
159 }
160
161 /**
162 * Starts the demo.
163 *
164 * @throws IOException if an I/O related error occurs
165 */
166 public void start() throws IOException {
167
168 // get the default Session
169 Session session = DemoSMimeUtil.getSession();
170
171
172 try {
173
174 // we use a binary canonicalizer
175 SMimeParameters.setCanonicalizer(new BinaryCanonicalizer());
176 // Create a demo Multipart
177 MimeBodyPart mbp1 = new SMimeBodyPart();
178 mbp1.setText("This is a Test of the IAIK S/MIME implementation!\n\n");
179 // attachment
180 MimeBodyPart attachment = new SMimeBodyPart();
181 attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
182 attachment.setFileName("test.html");
183
184 Multipart mp = new SMimeMultipart();
185 mp.addBodyPart(mbp1);
186 mp.addBodyPart(attachment);
187 DataHandler multipart = new DataHandler(mp, mp.getContentType());
188
189 Message msg; // the message to send
190 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
191 ByteArrayInputStream bais; // we read from a stream
192
193
194
195 // create explicitly signed message
196 msg = createSignedMessage(session, multipart);
197 System.out.println("creating explicitly 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 } catch (Exception ex) {
209 ex.printStackTrace();
210 throw new RuntimeException(ex.toString());
211 } finally {
212 // reset to default canonicalizer
213 SMimeParameters.setCanonicalizer(new DefaultCanonicalizer());
214 }
215
216 }
217
218 /**
219 * Creates a signed message.
220 *
221 * @param session the mail session
222 * @param dataHandler the content of the message to be signed
223 *
224 * @return the signed message
225 *
226 * @throws MessagingException if an error occurs when creating the message
227 */
228 public Message createSignedMessage(Session session, DataHandler dataHandler)
229 throws MessagingException {
230
231 String subject = "IAIK-S/MIME: Explicitly Signed";
232
233 MimeMessage msg = new MimeMessage(session);
234 msg.setFrom(new InternetAddress(from_));
235 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to_, false));
236 msg.setSentDate(new Date());
237 msg.setSubject(subject);
238
239 SignedContent sc = new SignedContent(false);
240
241 // set content
242 sc.setDataHandler(dataHandler);
243 sc.setCertificates(signerCertificates_);
244
245 try {
246 sc.addSigner((RSAPrivateKey)signerPrivateKey_, signerCertificate_);
247 } catch (NoSuchAlgorithmException ex) {
248 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
249 }
250
251 msg.setContent(sc, sc.getContentType());
252 // let the SignedContent update some message headers
253 sc.setHeaders(msg);
254 return msg;
255 }
256
257
258 /**
259 * Prints a dump of the given message to System.out.
260 *
261 * @param msg the message to be dumped to System.out
262 */
263 private static void printMessage(Message msg) throws IOException {
264 System.out.println("------------------------------------------------------------------");
265 System.out.println("Message dump: \n");
266 try {
267 msg.writeTo(System.out);
268 } catch (MessagingException ex) {
269 throw new IOException(ex.getMessage());
270 }
271 System.out.println("\n------------------------------------------------------------------");
272 }
273
274
275 /**
276 * The main method.
277 */
278 public static void main(String[] argv) throws IOException {
279
280 DemoSMimeUtil.initDemos();
281 (new BinarySignedDemo()).start();
282 System.out.println("\nReady!");
283 DemoUtil.waitKey();
284 }
285 }