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