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}