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/ess/SecurityLabelDemo.java 17 12.02.25 17:59 Dbratko $
059 // $Revision: 17 $
060 //
061
062 package demo.smime.ess;
063
064 import iaik.asn1.structures.AlgorithmID;
065 import iaik.asn1.structures.Attribute;
066 import iaik.cms.Utils;
067 import iaik.smime.SMimeSignerInfo;
068 import iaik.smime.SignedContent;
069 import iaik.smime.ess.ESSSecurityLabel;
070 import iaik.smime.ess.SecurityLabelException;
071 import iaik.x509.X509Certificate;
072
073 import java.io.ByteArrayInputStream;
074 import java.io.ByteArrayOutputStream;
075 import java.io.IOException;
076 import java.io.InputStream;
077 import java.security.PrivateKey;
078 import java.security.SignatureException;
079 import java.util.Date;
080
081 import javax.mail.Message;
082 import javax.mail.MessagingException;
083 import javax.mail.Session;
084 import javax.mail.internet.InternetAddress;
085 import javax.mail.internet.MimeMessage;
086
087 import demo.DemoSMimeUtil;
088 import demo.DemoUtil;
089 import demo.keystore.CMSKeyStore;
090
091 /**
092 * Demonstrates the usage of the S/MIME-ESS SecurityLabel attribute.
093 * The {@link iaik.smime.ess.ESSSecurityLabel SecurityLabel} attribute may be
094 * included as signed attribute in a {@link iaik.cms.SignerInfo SignerInfo} for
095 * providing some kind of "access control" mechanism for the contents of a message.
096 * <p>
097 * This demo uses a simple {@link demo.smime.ess.MySecurityLabelHandler
098 * SecurityLabelHandler} that only implements a simple security policy based on
099 * the default security classifications "unmarked", "unclassified", "restricted",
100 * "confidential", "secret", "top-secret". Since the SignedData message created
101 * by this demo only contains an ESS {@link iaik.smime.ess.ESSSecurityLabel
102 * SecurityLabel} attribute with classification "confidential", only this
103 * classification is processed by the {@link demo.smime.ess.MySecurityLabelHandler
104 * demo handler}. "unmarked" and "unclassified" are handled as "not critical"
105 * content (i.e. the content can be accessed by any one), "secret", "top-secret"
106 * lock the content (i.e. it is not displayed), and "restricted" and
107 * "confidential" popup a confirmation dialog reminding the recipient about
108 * the confidentiality of the message content.
109 * <p>
110 * To run this demo the following packages are required:
111 * <ul>
112 * <li>
113 * <code>iaik_cms.jar</code>
114 * </li>
115 * <li>
116 * <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>).
117 * </li>
118 * <li>
119 * <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
120 * </li>
121 * <li>
122 * <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).
123 * </li>
124 * </ul>
125 *
126 * @see demo.smime.ess.MySecurityLabelHandler
127 * @see iaik.smime.ess.ESSSecurityLabel
128 */
129 public class SecurityLabelDemo {
130
131 // whether to print dump all generates test messages to System.out
132 final static boolean PRINT_MESSAGES = false;
133
134 String firstName = "John";
135 String lastName = "SMime";
136 String to = "smimetest@iaik.at"; // email recipient
137 String from = "smimetest@iaik.at"; // email sender
138 String host = "mailhost"; // name of the mailhost
139
140 X509Certificate[] signerCertificates; // list of certificates to include in the S/MIME message
141 X509Certificate signerCertificate; // certificate of the signer/sender
142 PrivateKey signerPrivateKey; // private key of the signer/sender
143 X509Certificate encryptionCertOfSigner; // signer uses different certificate for encryption
144
145
146 /**
147 * Default constructor. Reads certificates and keys from the demo keystore.
148 */
149 public SecurityLabelDemo() {
150
151 System.out.println();
152 System.out.println("******************************************************************************************");
153 System.out.println("* SecurityLabelDemo demo *");
154 System.out.println("* (shows how to handle the ESS SecurityLabel attribute) *");
155 System.out.println("******************************************************************************************");
156 System.out.println();
157
158 // get the certificates from the KeyStore
159 signerCertificates = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
160 signerPrivateKey = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1);
161 signerCertificate = signerCertificates[0];
162 encryptionCertOfSigner = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0];
163 }
164
165 /**
166 * Starts the demo.
167 *
168 * @throws IOException if an I/O related error occurs
169 */
170 public void start() throws IOException {
171
172 // get the default Session
173 Session session = DemoSMimeUtil.getSession();
174
175 try {
176 Message msg; // the message to send
177 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
178 ByteArrayInputStream bais; // we read from a stream
179
180 msg = createSignedMessage(session);
181 System.out.println("creating implicitly signed message...");
182 baos.reset();
183 // send, write
184 msg.saveChanges();
185 msg.writeTo(baos);
186
187 // receive, parse
188 bais = new ByteArrayInputStream(baos.toByteArray());
189 msg = new MimeMessage(session, bais);
190 if (PRINT_MESSAGES) {
191 printMessage(msg);
192 }
193 parseMessage(msg);
194
195 } catch (Exception ex) {
196 ex.printStackTrace();
197 throw new RuntimeException(ex.toString());
198 }
199 }
200
201 /**
202 * Creates a MIME message container with the given subject for the given session.
203 *
204 * @param session the mail sesion
205 * @param subject the subject of the message
206 *
207 * @return the MIME message with FROM, TO, DATE and SUBJECT headers (without content)
208 *
209 * @throws MessagingException if the message cannot be created
210 */
211 public Message createMessage(Session session, String subject) throws MessagingException {
212 MimeMessage msg = new MimeMessage(session);
213 msg.setFrom(new InternetAddress(from));
214 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false));
215 msg.setSentDate(new Date());
216 msg.setSubject(subject);
217 return msg;
218 }
219
220 /**
221 * Creates a signed message containing an ESS SecurityLabel attribute.
222 *
223 * @param session the mail session
224 * @return the signed message
225 *
226 * @throws Exception if an error occurs when creating the message
227 */
228 public Message createSignedMessage(Session session) throws Exception {
229
230 String subject = "IAIK-S/MIME: SecurityLabelDemo (Explicitly Signed)";
231 StringBuffer buf = new StringBuffer();
232 buf.append("This is an explicitly signed message\n");
233 buf.append("containing an ESSSecurityLabel attribute.\n");
234
235 Message msg = createMessage(session, subject);
236
237 SignedContent sc = new SignedContent(true);
238 // set the content
239 sc.setText(buf.toString());
240
241 // set the signer certificates
242 sc.setCertificates(signerCertificates);
243 // set SignerInfo
244 SMimeSignerInfo signerInfo = new SMimeSignerInfo(signerCertificate,
245 (AlgorithmID)AlgorithmID.sha256.clone(),
246 (AlgorithmID)AlgorithmID.rsaEncryption.clone(),
247 signerPrivateKey,
248 encryptionCertOfSigner,
249 true);
250
251 // add SecurityLabel attribute
252 ESSSecurityLabel securityLabel = new ESSSecurityLabel(MySecurityLabelHandler.MY_SECURITY_POLICY_ID);
253 securityLabel.setSecurityClassification(ESSSecurityLabel.CONFIDENTIAL);
254 securityLabel.setPrivacyMarkString("HIGH CONFIDENTIAL DATA MATERIAL! RESTRICTED USER ACCESS");
255 signerInfo.addSignedAttribute(new Attribute(securityLabel));
256 sc.addSigner(signerInfo);
257 msg.setContent(sc, sc.getContentType());
258 // let the SignedContent update some message headers
259 sc.setHeaders(msg);
260 return msg;
261 }
262
263 /**
264 * Parses the signed message, verifies the signature and processes the SecurityLabel
265 * attribute.
266 *
267 * @param msg the message to be parsed
268 *
269 * @throws IOException if an I/O related problem occurs
270 * @throws MessagingException if there is a problem with the message format
271 * @throws SignatureException if the signature verification failes
272 */
273 public void parseMessage(Message msg) throws IOException, MessagingException, SignatureException {
274 // we know that we have a signed message
275 SignedContent sc = (SignedContent)msg.getContent();
276 // set a SecurityLabelHandler
277 sc.setSecurityLabelHandler(new MySecurityLabelHandler());
278 // verify signature
279 X509Certificate signer = null;
280 try {
281 signer = sc.verify();
282 System.out.println("This message is signed from: "+signer.getSubjectDN());
283 } catch (SignatureException ex) {
284 throw new SignatureException("Signature verification error: " + ex.toString());
285 }
286 // try to access the content data
287 try {
288 Object content = sc.getContent();
289 System.out.println("Included content:");
290 // depending on JavaMail API version we may have a String or a InputStream
291 if (content instanceof String) {
292 System.out.println(content);
293 } else if (content instanceof InputStream) {
294 ByteArrayOutputStream baos = new ByteArrayOutputStream();
295 Utils.copyStream((InputStream)content, baos, null);
296 System.out.println(new String(baos.toByteArray()));
297 }
298 } catch (SecurityLabelException ex) {
299 System.out.println(ex.getMessage());
300 }
301 }
302
303
304 /**
305 * Prints a dump of the given message to System.out.
306 *
307 * @param msg the message to be dumped to System.out
308 */
309 private static void printMessage(Message msg) throws IOException {
310 System.out.println("------------------------------------------------------------------");
311 System.out.println("Message dump: \n");
312 try {
313 msg.writeTo(System.out);
314 } catch (MessagingException ex) {
315 throw new IOException(ex.getMessage());
316 }
317 System.out.println("\n------------------------------------------------------------------");
318 }
319
320
321 /**
322 * The main method.
323 */
324 public static void main(String[] argv) throws IOException {
325
326 DemoSMimeUtil.initDemos();
327 try {
328 (new SecurityLabelDemo()).start();
329 } catch (Exception ex) {
330 ex.printStackTrace();
331 }
332
333 System.out.println("\nReady!");
334 DemoUtil.waitKey();
335
336 }
337 }