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/MLADemo.java 49    12.02.25 17:59 Dbratko $
059    // $Revision: 49 $
060    //
061    
062    package demo.smime.ess;
063    
064    import iaik.asn1.CodingException;
065    import iaik.asn1.structures.AlgorithmID;
066    import iaik.asn1.structures.Attribute;
067    import iaik.asn1.structures.Attributes;
068    import iaik.cms.CMSSignatureException;
069    import iaik.cms.IssuerAndSerialNumber;
070    import iaik.cms.KeyTransRecipientInfo;
071    import iaik.cms.RecipientInfo;
072    import iaik.cms.SignerInfo;
073    import iaik.cms.Utils;
074    import iaik.smime.EncryptedContent;
075    import iaik.smime.SMimeBodyPart;
076    import iaik.smime.SMimeException;
077    import iaik.smime.SMimeMultipart;
078    import iaik.smime.SMimeUtil;
079    import iaik.smime.SignedContent;
080    import iaik.smime.ess.ESSException;
081    import iaik.smime.ess.EntityIdentifier;
082    import iaik.smime.ess.MLData;
083    import iaik.smime.ess.MLExpansionHistory;
084    import iaik.smime.ess.MLReceiptPolicy;
085    import iaik.smime.ess.utils.ESSLayerException;
086    import iaik.smime.ess.utils.ESSLayers;
087    import iaik.smime.ess.utils.KeyStoreDatabase;
088    import iaik.smime.ess.utils.MLA;
089    import iaik.utils.CryptoUtils;
090    import iaik.x509.X509Certificate;
091    
092    import java.io.ByteArrayInputStream;
093    import java.io.ByteArrayOutputStream;
094    import java.io.IOException;
095    import java.security.NoSuchAlgorithmException;
096    import java.security.PrivateKey;
097    import java.util.Date;
098    
099    import javax.activation.DataHandler;
100    import javax.activation.DataSource;
101    import javax.activation.FileDataSource;
102    import javax.mail.BodyPart;
103    import javax.mail.Message;
104    import javax.mail.MessagingException;
105    import javax.mail.Multipart;
106    import javax.mail.Session;
107    import javax.mail.internet.InternetAddress;
108    import javax.mail.internet.MimeBodyPart;
109    import javax.mail.internet.MimeMessage;
110    
111    import demo.DemoSMimeUtil;
112    import demo.DemoUtil;
113    import demo.keystore.CMSKeyStore;
114    import demo.keystore.CMSKeyStoreConstants;
115    
116    /**
117     * A ESS mailing list agent (MLA) demo.
118     * Demonstrates the usage of the {@link iaik.smime.ess.utils.MLA MLA} utility by
119     * means of the examples given in <a href="https://www.rfc-editor.org/rfc/rfc2634.html" target = "_blank">RFC2634</a>,
120     * section 4.2.1:
121     * <pre>
122     * 4.2.1 Examples of Rule Processing
123     *
124     * The following examples help explain the rules above:
125     *
126     * 1) A message (S1(Original Content)) (where S = SignedData) is sent to
127     *    the MLA in which the signedData layer does not include an
128     *    MLExpansionHistory attribute. The MLA verifies and fully processes
129     *    the signedAttributes in S1.  The MLA decides that there is not an
130     *    original, received "outer" signedData layer since it finds the
131     *    original content, but never finds an envelopedData and never finds
132     *    an mlExpansionHistory attribute. The MLA calculates a new
133     *    signedData layer, S2, resulting in the following message sent to
134     *    the ML recipients: (S2(S1(Original Content))). The MLA includes an
135     *    mlExpansionHistory attribute in S2.
136     *
137     * 2) A message (S3(S2(S1(Original Content)))) is sent to the MLA in
138     *    which none of the signedData layers includes an MLExpansionHistory
139     *    attribute. The MLA verifies and fully processes the
140     *    signedAttributes in S3, S2 and S1. The MLA decides that there is
141     *    not an original, received "outer" signedData layer since it finds
142     *    the original content, but never finds an envelopedData and never
143     *    finds an mlExpansionHistory attribute. The MLA calculates a new
144     *    signedData layer, S4, resulting in the following
145     *    message sent to the ML recipients:
146     *    (S4(S3(S2(S1(Original Content))))). The MLA includes an
147     *    mlExpansionHistory attribute in S4.
148     *
149     * 3) A message (E1(S1(Original Content))) (where E = envelopedData) is
150     *    sent to the MLA in which S1 does not include an MLExpansionHistory
151     *    attribute.  The MLA decides that there is not an original,
152     *    received "outer" signedData layer since it finds the E1 as the
153     *    outer layer.  The MLA expands the recipientInformation in E1. The
154     *    MLA calculates a new signedData layer, S2, resulting in the
155     *    following message sent to the ML recipients:
156     *    (S2(E1(S1(Original Content)))). The MLA includes an
157     *    mlExpansionHistory attribute in S2.
158     *
159     * 4) A message (S2(E1(S1(Original Content)))) is sent to the MLA in
160     *    which S2 includes an MLExpansionHistory attribute. The MLA verifies
161     *    the signature and fully processes the signedAttributes in S2. The
162     *    MLA finds the mlExpansionHistory attribute in S2, so it decides
163     *    that S2 is the "outer" signedData. The MLA remembers the
164     *    signedAttributes included in S2 for later inclusion in the new
165     *    outer signedData that it applies to the message. The MLA strips off
166     *    S2. The MLA then expands the recipientInformation in E1 (this
167     *    invalidates the signature in S2 which is why it was stripped). The
168     *    nMLA calculates a new signedData layer, S3, resulting in the
169     *    following message sent to the ML recipients: (S3(E1(S1(Original
170     *    Content)))). The MLA includes in S3 the attributes from S2 (unless
171     *    it specifically replaces an attribute value) including an updated
172     *    mlExpansionHistory attribute.
173     *
174     * 5) A message (S3(S2(E1(S1(Original Content))))) is sent to the MLA in
175     *    which none of the signedData layers include an MLExpansionHistory
176     *    attribute. The MLA verifies the signature and fully processes the
177     *    signedAttributes in S3 and S2. When the MLA encounters E1, then it
178     *    decides that S2 is the "outer" signedData since S2 encapsulates E1.
179     *    The MLA remembers the signedAttributes included in S2 for later
180     *    inclusion in the new outer signedData that it applies to the
181     *    message.  The MLA strips off S3 and S2. The MLA then expands the
182     *    recipientInformation in E1 (this invalidates the signatures in S3
183     *    and S2 which is why they were stripped). The MLA calculates a new
184     *    signedData layer, S4, resulting in the following message sent to
185     *    the ML recipients: (S4(E1(S1(Original Content)))). The MLA
186     *    includes in S4 the attributes from S2 (unless it specifically
187     *    replaces an attribute value) and includes a new
188     *    mlExpansionHistory attribute.
189     *
190     * 6) A message (S3(S2(E1(S1(Original Content))))) is sent to the MLA in
191     *    which S3 includes an MLExpansionHistory attribute. In this case,
192     *    the MLA verifies the signature and fully processes the
193     *    signedAttributes in S3. The MLA finds the mlExpansionHistory in S3,
194     *    so it decides that S3 is the "outer" signedData. The MLA remembers
195     *    the signedAttributes included in S3 for later inclusion in the new
196     *    outer signedData that it applies to the message. The MLA keeps on
197     *    parsing encapsulated layers because it must determine if there are
198     *    any eSSSecurityLabel attributes contained within. The MLA verifies
199     *    the signature and fully processes the signedAttributes in S2. When
200     *    the MLA encounters E1, then it strips off S3 and S2. The MLA then
201     *    expands the recipientInformation in E1 (this invalidates the
202     *    signatures in S3 and S2 which is why they were stripped). The MLA
203     *    calculates a new signedData layer, S4, resulting in the following
204     *    message sent to the ML recipients: (S4(E1(S1(Original Content)))).
205     *    The MLA includes in S4 the attributes from S3 (unless it
206     *    specifically replaces an attribute value) including an updated
207     *    mlExpansionHistory attribute.
208     * </pre>
209     * To run this demo the following packages are required:
210     * <ul>
211     *    <li>
212     *       <code>iaik_cms.jar</code>
213     *    </li>
214     *    <li>
215     *       <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>).
216     *    </li>
217     *    <li>
218     *       <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>).
219     *    </li>   
220     *    <li>
221     *       <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 &lt; 1.6).
222     *    </li> 
223     * </ul>
224     * 
225     * @see iaik.smime.ess.MLExpansionHistory
226     * @see iaik.smime.ess.MLData
227     * @see iaik.smime.ess.MLReceiptPolicy
228     * @see iaik.smime.ess.utils.MLA
229     */
230    public class MLADemo {
231      // whether to print dump all generates test messages to System.out
232      final static boolean DUMP_MESSAGES = false;
233      
234      // the first party (that sends a message to the MLA)
235      String senderName_ = "IAIK Demo Sender";
236      // the second party (MLA)
237      String mlaName_ = "IAIK Demo ML Agent";
238      // the third final party (that receives a message from the MLA)
239      String recipientName_ = "IAIK Demo Recipient";
240      // we use the same email address for all parties
241      String senderAddress_ = "\""+senderName_+"\" <smimetest@iaik.at>";
242      String mlaAddress_ = "\""+mlaName_+"\" <smimetest@iaik.at>";
243      String recipientAddress_ = "\""+recipientName_+"\" <smimetest@iaik.at>";
244      String host_ = "mailhost";                       // name of the mailhost
245      
246      // required certificate; read from the demo keystore
247      X509Certificate[] signerCertificatesOfS1_;            // signer certificates of entity S1
248      PrivateKey signerPrivateKeyOfS1_;                     // signer private key of entity S1
249      X509Certificate[] signerCertificatesOfS2_;            // signer certificates of entity S2
250      PrivateKey signerPrivateKeyOfS2_;                     // signer private key of entity S2
251      X509Certificate[] signerCertificatesOfS3_;            // signer certificates of entity S3
252      PrivateKey signerPrivateKeyOfS3_;                     // signer private key of entity S3
253      X509Certificate[] signerCertificatesOfMLA_;           // signer certificates of MLA
254      PrivateKey signerPrivateKeyOfMLA_;                    // signer private key of MLA
255      X509Certificate[] encryptionCertificatesOfMLA_;       // encryption certificates of MLA
256      PrivateKey encryptionPrivateKeyOfMLA_;                // encryption private key of MLA
257      X509Certificate[] certificatesOfMLA_;                 // all (signer + encryption) certificates of the MLA
258      X509Certificate[] encryptionCertificatesOfE1_;        // encryption certificates of entity E1
259      PrivateKey encryptionPrivateKeyOfE1_;                 // encryption private key of entity E1
260      X509Certificate[] recipientCertificates_;             // certificates of the final recipient if the MLA encrypts again
261      PrivateKey recipientPrivateKey_;                      // private key of the final recipient if the MLA encrypts again
262      
263      
264      // keystore data base of the MLA
265      KeyStoreDatabase keyStoreDatabase_;
266      // MLA 
267      MLA mla_;
268      // MLA id
269      EntityIdentifier mlaID_;
270      
271      /**
272       * Empty default constructor. Reads all required keys and certificates
273       * from the demo keystore (created by running @link demo.keystore.SetupCMSKeySrore)
274       * stored at "cms.keystore" in your current working directoy. Inits the ML agent.
275       */ 
276      public MLADemo() {
277        
278        System.out.println();
279        System.out.println("******************************************************************************************");
280        System.out.println("*                                      MLADemo                                           *");
281        System.out.println("*    (shows the usage of the IAIK-CMS MLA utility for running an ESS mail list agent)    *");
282        System.out.println("******************************************************************************************");
283        System.out.println();
284        
285        try {
286          keyStoreDatabase_ = new KeyStoreDatabase();
287          // get the certificates from the KeyStore
288          signerCertificatesOfS1_ = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1);
289          signerPrivateKeyOfS1_ = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1);
290          signerCertificatesOfS2_ = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_3072_SIGN);
291          signerPrivateKeyOfS2_ = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_3072_SIGN);
292          signerCertificatesOfS3_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_2);
293          signerPrivateKeyOfS3_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_2);
294          signerCertificatesOfMLA_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_3);
295          signerPrivateKeyOfMLA_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_3);
296          encryptionCertificatesOfMLA_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
297          encryptionPrivateKeyOfMLA_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1);
298          encryptionCertificatesOfE1_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2);
299          encryptionPrivateKeyOfE1_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2);
300          recipientCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_3);
301          recipientPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_3);  
302        
303          // add the certificates and keys of the MLA to its key data base
304          keyStoreDatabase_.addKey(signerPrivateKeyOfMLA_, signerCertificatesOfMLA_, CMSKeyStoreConstants.RSA_2048_SIGN_1);
305          keyStoreDatabase_.addKey(encryptionPrivateKeyOfMLA_, encryptionCertificatesOfMLA_, CMSKeyStoreConstants.RSA_2048_CRYPT_1);
306        
307          // init MLA 
308          mlaID_ = new EntityIdentifier(new IssuerAndSerialNumber(signerCertificatesOfMLA_[0]));
309          mla_ = new MLA(mlaID_);
310          mla_.setDebugStream("MLA", System.out);
311          // to whom the MLA wants to send an encrypted message
312          mla_.setEncryptionInfo(null, 
313                                 new RecipientInfo[] { new KeyTransRecipientInfo(recipientCertificates_[0], (AlgorithmID)AlgorithmID.rsaEncryption.clone()) },
314                                 (AlgorithmID)AlgorithmID.aes256_CBC.clone(), 
315                                 256);
316          mla_.setDebugStream("MLA", System.out);
317          mla_.setKeyDatabase(keyStoreDatabase_);
318          // do not continue to resolve a message if there is an invalid signature in a signed layer
319          mla_.setStopOnInvalidSignature(true);                           
320          System.out.println("MLA signing cert is: " + signerCertificatesOfMLA_[0].getSubjectDN());
321          System.out.println("MLA entity identifier is:\n" + mlaID_ + "\n");
322        } catch (Exception ex) {  
323          ex.printStackTrace();
324              throw new RuntimeException(ex.toString());
325            } 
326      
327      }
328    
329      /**
330       * Runs the demo samples.
331       */
332      public void start() {
333        
334        try {
335          
336          // get the default Session
337              Session session = DemoSMimeUtil.getSession();
338    
339              // Create a demo Multipart
340          MimeBodyPart mbp1 = new SMimeBodyPart();
341              mbp1.setText("This is a test of the IAIK-CMS S/MIME ESS MLA implementation.\n");
342              // try to test an attachment
343          MimeBodyPart attachment = new SMimeBodyPart();
344          attachment.setDataHandler(new DataHandler(new FileDataSource("test.html")));
345          attachment.setFileName("test.html");
346          Multipart mp = new SMimeMultipart();
347          mp.addBodyPart(mbp1);
348          mp.addBodyPart(attachment);
349        
350          // whether to create implcit (content included) or explicit signed messages
351          boolean implicit = true;  
352          System.out.println("Implicit demos");
353          
354          // keep original datasource for comparison 
355          MimeMessage tmpMsg = new MimeMessage(session);
356          tmpMsg.setContent(mp);
357          tmpMsg.saveChanges();
358          byte[] dsBytes = getDataSource(tmpMsg.getDataHandler());
359    
360          System.out.println("Testing sample 4.2.1,1) from RFC 2634: S1(O) ==> S2(S1(O))");
361          test_S1_O(session, mp, dsBytes, implicit);  
362               
363          System.out.println("Testing sample 4.2.1,2) from RFC 2634: S3(S2(S1(O))) ==> S4(S3(S2(S1(O))))");
364          test_S3_S2_S1_O(session, mp, dsBytes, implicit);  
365    
366          System.out.println("Testing sample 4.2.1,3) from RFC 2634: E1(S1(O)) ==> S2(E1(S1(O)))");
367          test_E1_S1_O(session, mp, dsBytes, implicit);  
368    
369          System.out.println("Testing sample 4.2.1,4) from RFC 2634: S2(E1(S1(O))) ==> S3(E1(S1(O)))");
370          test_S2_E1_S1_O(session, mp, dsBytes, implicit);
371    
372          System.out.println("Testing sample 4.2.1,5) from RFC 2634: S3(S2(E1(S1(O)))) ==> S4(E1(S1(O)))");
373          test_S3_S2_E1_S1_O(session, mp, dsBytes, implicit, false);
374    
375          System.out.println("Testing sample 4.2.1,6) from RFC 2634: S3(S2(E1(S1(O)))) ==> S4(E1(S1(O)))");
376          test_S3_S2_E1_S1_O(session, mp, dsBytes, implicit, true);
377          
378          implicit = false;  
379          System.out.println("Explicit demos");
380                
381          System.out.println("Testing sample 4.2.1,1) from RFC 2634: S1(O) ==> S2(S1(O))");
382          test_S1_O(session, mp, dsBytes, implicit);  
383               
384          System.out.println("Testing sample 4.2.1,2) from RFC 2634: S3(S2(S1(O))) ==> S4(S3(S2(S1(O))))");
385          test_S3_S2_S1_O(session, mp, dsBytes, implicit);  
386    
387          System.out.println("Testing sample 4.2.1,3) from RFC 2634: E1(S1(O)) ==> S2(E1(S1(O)))");
388          test_E1_S1_O(session, mp, dsBytes, implicit);  
389    
390          System.out.println("Testing sample 4.2.1,4) from RFC 2634: S2(E1(S1(O))) ==> S3(E1(S1(O)))");
391          test_S2_E1_S1_O(session, mp, dsBytes, implicit);
392    
393          System.out.println("Testing sample 4.2.1,5) from RFC 2634: S3(S2(E1(S1(O)))) ==> S4(E1(S1(O)))");
394          test_S3_S2_E1_S1_O(session, mp, dsBytes, implicit, false);
395    
396          System.out.println("Testing sample 4.2.1,6) from RFC 2634: S3(S2(E1(S1(O)))) ==> S4(E1(S1(O)))");
397          test_S3_S2_E1_S1_O(session, mp, dsBytes, implicit, true);
398    
399          System.out.println("Ready!");
400          
401        } catch (Exception ex) {  
402          ex.printStackTrace();
403              throw new RuntimeException(ex.toString());
404            }  
405      }
406        
407      /**
408       * Tests the MLA behaviour for a simple signed message according to sample 4.2.1,1) of
409       * <a href="https://www.rfc-editor.org/rfc/rfc2634.html" target = "_blank">RFC2634</a>:
410       * <pre>
411       * A message (S1(Original Content)) (where S = SignedData) is sent to
412       * the MLA in which the signedData layer does not include an
413       * MLExpansionHistory attribute. The MLA verifies and fully processes
414       * the signedAttributes in S1.  The MLA decides that there is not an
415       * original, received "outer" signedData layer since it finds the
416       * original content, but never finds an envelopedData and never finds
417       * an mlExpansionHistory attribute. The MLA calculates a new
418       * signedData layer, S2, resulting in the following message sent to
419       * the ML recipients: (S2(S1(Original Content))). The MLA includes an
420       * mlExpansionHistory attribute in S2.
421       * </pre>
422       * 
423       * @param session the current mail session
424       * @param mp the multipart content
425       * @param dsBytes the original content dataSorce bytes for comparison
426       * @param implicit whether implicit (content included) or explicit signing shall be used
427       *
428       * @throws Exception if an error coours
429       */
430      public void test_S1_O(Session session, Multipart mp, byte[] dsBytes, boolean implicit) throws Exception {
431        //  RFC2634, 4.2.1, 1) S1(Original Content) ==> MLA(S1(Original Content)
432        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
433        ByteArrayInputStream bais;  // we read from a stream
434        
435        // 1. send signed message to MLA
436        System.out.println("1. Creating signed message and send it to MLA...");
437        Message msg = createMessage(session, senderAddress_, mlaAddress_);
438        msg.setSubject("RFC2634, 4.2.1, 1) S1(Original Content)");
439        SignedContent sc = create_S1_O(mp, 
440                                       mp.getContentType(), 
441                                       implicit,
442                                       signerCertificatesOfS1_,
443                                       signerPrivateKeyOfS1_,
444                                       (AlgorithmID)AlgorithmID.sha256.clone(),
445                                       (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(),
446                                       null); 
447        msg.setContent(sc, sc.getContentType());                                
448        sc.setHeaders(msg);
449        msg.saveChanges();
450        baos.reset();
451        msg.writeTo(baos);
452        // 2. MLA: receives messages, processes it and creates and sends a new signed message
453        System.out.println("2. MLA: Processing message...");
454        bais = new ByteArrayInputStream(baos.toByteArray());
455        msg = new MimeMessage(session, bais);
456        if (DUMP_MESSAGES) {
457          System.out.println("Received message:");  
458          dumpMessage(msg);
459        }  
460        sc = processMessageForMLA(msg, implicit, "S1_O");
461        System.out.println("MLA: Sending signed message to new recipient.");
462        msg = createMessage(session, mlaAddress_, recipientAddress_);
463        msg.setSubject("RFC2634, 4.2.1, 1) MLA(S1(Original Content)");
464        msg.setContent(sc, sc.getContentType());
465        sc.setHeaders(msg);
466        baos.reset();
467        msg.writeTo(baos);
468        // 3. final recipient: receives message from MLA, parses it and verifies the signature
469        System.out.println("3. Final recipient: Parsing message received from MLA...");
470        bais = new ByteArrayInputStream(baos.toByteArray());
471        msg = new MimeMessage(session, bais);
472        if (DUMP_MESSAGES) {
473          dumpMessage(msg);
474        }    
475        // message must be signed by MLA: S2(S1(O)), checking signature S2
476        Object content = msg.getContent();
477        if ((content instanceof SignedContent == false)) {
478          throw new ESSException("Error: received message is not signed!");
479        }  
480        System.out.println("First layer of message is signed. Verifying signature.");
481        DataHandler dh = verify((SignedContent)content, signerCertificatesOfMLA_[0]);
482        // read MLExpansionHistory attribute, must contain one MLData entry
483        System.out.println("Reading MLExpansionHistory attribute.");
484        readMLExpansionHistory((SignedContent)content, 1);
485        // second layer must be signed, too
486        content = dh.getContent();
487        if ((content instanceof SignedContent == false)) {
488          throw new ESSException("Error: second layer of received message is not signed!");
489        }  
490        System.out.println("Second layer of message is signed. Verifying signature.");
491        dh = verify((SignedContent)content, signerCertificatesOfS1_[0]);
492        // check content
493        if (CryptoUtils.equalsBlock(dsBytes, getDataSource(dh)) == false) {
494          throw new Exception("Error: Original content changed!"); 
495        }  
496        dumpContent(dh);
497      }  
498      
499      
500      /**
501       * Tests the MLA behaviour for a triple signed message according to sample 4.2.1,2) of
502       * <a href="https://www.rfc-editor.org/rfc/rfc2634.html" target = "_blank">RFC2634</a>:
503       * <pre>
504       * A message (S3(S2(S1(Original Content)))) is sent to the MLA in
505       * which none of the signedData layers includes an MLExpansionHistory
506       * attribute. The MLA verifies and fully processes the
507       * signedAttributes in S3, S2 and S1. The MLA decides that there is
508       * not an original, received "outer" signedData layer since it finds
509       * the original content, but never finds an envelopedData and never
510       * finds an mlExpansionHistory attribute. The MLA calculates a new
511       * signedData layer, S4, resulting in the following message sent to
512       * the ML recipients: (S4(S3(S2(S1(Original Content))))). The MLA 
513       * includes an mlExpansionHistory attribute in S4.
514       * </pre>
515       * 
516       * @param session the current mail session
517       * @param mp the multipart content
518       * @param dsBytes the original content dataSorce bytes for comparison
519       * @param implicit whether implicit (content included) or explicit signing shall be used
520       *
521       * @throws Exception if an error coours
522       */
523      public void test_S3_S2_S1_O(Session session, Multipart mp, byte[] dsBytes, boolean implicit) throws Exception {
524        //  RFC2634, 4.2.1, 2) S3(S2(S1(Original Content))) ==> MLA(S3(S2(S1(Original Content))))
525        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
526        ByteArrayInputStream bais;  // we read from a stream
527        
528        // 1. send signed message to MLA
529        System.out.println("1. Creating signed message and send it to MLA...");
530        Message msg = createMessage(session, senderAddress_, mlaAddress_);
531        msg.setSubject("RFC2634, 4.2.1, 2) S3(S2(S1(Original Content)))");
532        SignedContent sc = create_S3_S2_S1_O(mp, 
533                                             mp.getContentType(), 
534                                             implicit,
535                                             signerCertificatesOfS1_,
536                                             signerPrivateKeyOfS1_,
537                                             (AlgorithmID)AlgorithmID.sha256.clone(),
538                                             (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(),
539                                             null,
540                                             implicit,
541                                             signerCertificatesOfS2_,
542                                             signerPrivateKeyOfS2_,
543                                             (AlgorithmID)AlgorithmID.sha256.clone(),
544                                             (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(),
545                                             null,
546                                             implicit,
547                                             signerCertificatesOfS3_,
548                                             signerPrivateKeyOfS3_,
549                                             (AlgorithmID)AlgorithmID.sha256.clone(),
550                                             (AlgorithmID)AlgorithmID.rsaEncryption.clone(),
551                                             null); 
552        msg.setContent(sc, sc.getContentType());                                
553        sc.setHeaders(msg);
554        msg.saveChanges();
555        baos.reset();
556        msg.writeTo(baos);
557        // 2. MLA: receives messages, processes it and creates and sends a new signed message
558        System.out.println("2. MLA: Processing message...");
559        bais = new ByteArrayInputStream(baos.toByteArray());
560        msg = new MimeMessage(session, bais);
561        if (DUMP_MESSAGES) {
562          System.out.println("Received message:");  
563          dumpMessage(msg);
564        }  
565        sc = processMessageForMLA(msg, implicit, "S3_S2_S1_O");
566        System.out.println("MLA: Sending signed message to new recipient.");
567        msg = createMessage(session, mlaAddress_, recipientAddress_);
568        msg.setSubject("RFC2634, 4.2.1, 2) MLA(S3(S2(S1(Original Content))))");
569        msg.setContent(sc, sc.getContentType());
570        sc.setHeaders(msg);
571        baos.reset();
572        msg.writeTo(baos);
573        // 3. final recipient: receives message from MLA, parses it and verifies the signature
574        System.out.println("3. Final recipient: Parsing message received from MLA...");
575        bais = new ByteArrayInputStream(baos.toByteArray());
576        msg = new MimeMessage(session, bais);
577        if (DUMP_MESSAGES) {
578          dumpMessage(msg);
579        }    
580        // message must be signed by MLA: S4(S3(S2(S1(O)))), checking signature S2
581        Object content = msg.getContent();
582        if ((content instanceof SignedContent == false)) {
583          throw new ESSException("Error: received message is not signed!");
584        }  
585        System.out.println("First layer of message is signed. Verifying signature.");
586        DataHandler dh = verify((SignedContent)content, signerCertificatesOfMLA_[0]);
587        // read MLExpansionHistory attribute, must contain one MLData entry
588        System.out.println("Reading MLExpansionHistory attribute.");
589        readMLExpansionHistory((SignedContent)content, 1);
590        // second layer must be signed, too
591        content = dh.getContent();
592        if ((content instanceof SignedContent == false)) {
593          throw new ESSException("Error: second layer of received message is not signed!");
594        }  
595        System.out.println("Second layer of message is signed. Verifying signature.");
596        dh = verify((SignedContent)content, signerCertificatesOfS3_[0]);
597        // third layer must be signed, too
598        content = dh.getContent();
599        if ((content instanceof SignedContent == false)) {
600          throw new ESSException("Error: third layer of received message is not signed!");
601        }  
602        System.out.println("Third layer of message is signed. Verifying signature.");
603        dh = verify((SignedContent)content, signerCertificatesOfS2_[0]);
604        // fourth layer must be signed, too
605        content = dh.getContent();
606        if ((content instanceof SignedContent == false)) {
607          throw new ESSException("Error: fourth layer of received message is not signed!");
608        }  
609        System.out.println("Fourth layer of message is signed. Verifying signature.");
610        dh = verify((SignedContent)content, signerCertificatesOfS1_[0]);
611        // check content
612        if (CryptoUtils.equalsBlock(dsBytes, getDataSource(dh)) == false) {
613          throw new Exception("Error: Original content changed!"); 
614        }  
615        dumpContent(dh);
616      }
617      
618      /**
619       * Tests the MLA behaviour for a encrypted and signed signed message according to 
620       * sample 4.2.1,3) of <a href="https://www.rfc-editor.org/rfc/rfc2634.html" target = "_blank">RFC2634</a>:
621       * <pre>
622       * A message (E1(S1(Original Content))) (where E = envelopedData) is
623       * sent to the MLA in which S1 does not include an MLExpansionHistory
624       * attribute.  The MLA decides that there is not an original,
625       * received "outer" signedData layer since it finds the E1 as the
626       * outer layer.  The MLA expands the recipientInformation in E1. The
627       * MLA calculates a new signedData layer, S2, resulting in the
628       * following message sent to the ML recipients:
629       * (S2(E1(S1(Original Content)))). The MLA includes an
630       * mlExpansionHistory attribute in S2.
631       * </pre>
632       * 
633       * @param session the current mail session
634       * @param mp the multipart content
635       * @param dsBytes the original content dataSorce bytes for comparison
636       * @param implicit whether implicit (content included) or explicit signing shall be used
637       *
638       * @throws Exception if an error coours
639       */
640      public void test_E1_S1_O(Session session, Multipart mp, byte[] dsBytes, boolean implicit) throws Exception {
641        //  RFC2634, 4.2.1, 3) E1(S1(Original Content)) ==> MLA(E1(S1(Original Content)))
642        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
643        ByteArrayInputStream bais;  // we read from a stream
644        
645        // 1. send signed and encrypted message to MLA
646        System.out.println("1. Creating signed and encrypted message and send it to MLA...");
647        Message msg = createMessage(session, senderAddress_, mlaAddress_);
648        msg.setSubject("RFC2634, 4.2.1, 3) E1(S1(Original Content))");
649        EncryptedContent ec = create_E1_S1_O(mp, 
650                                          mp.getContentType(), 
651                                          implicit,
652                                          signerCertificatesOfS1_,
653                                          signerPrivateKeyOfS1_,
654                                          (AlgorithmID)AlgorithmID.sha256.clone(),
655                                          (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(),
656                                          null,
657                                          encryptionCertificatesOfMLA_[0],
658                                          (AlgorithmID)AlgorithmID.rsaEncryption,
659                                          (AlgorithmID)AlgorithmID.aes128_CBC.clone(),
660                                           128); 
661        msg.setContent(ec, ec.getContentType());                                
662        ec.setHeaders(msg);
663        msg.saveChanges();
664        baos.reset();
665        msg.writeTo(baos);
666        // 2. MLA: receives messages, processes it and creates and sends a new signed message
667        System.out.println("2. MLA: Processing message...");
668        bais = new ByteArrayInputStream(baos.toByteArray());
669        msg = new MimeMessage(session, bais);
670        if (DUMP_MESSAGES) {
671          System.out.println("Received message:");  
672          dumpMessage(msg);
673        }  
674        SignedContent sc = processMessageForMLA(msg, implicit, "E1_S1_O");
675        System.out.println("MLA: Sending signed message to new recipient.");
676        msg = createMessage(session, mlaAddress_, recipientAddress_);
677        msg.setSubject("RFC2634, 4.2.1, 3) MLA(E1(S1(Original Content)))");
678        msg.setContent(sc, sc.getContentType());
679        sc.setHeaders(msg);
680        baos.reset();
681        msg.writeTo(baos);
682        // 3. final recipient: receives message from MLA, parses it
683        System.out.println("3. Final recipient: Parsing message received from MLA...");
684        bais = new ByteArrayInputStream(baos.toByteArray());
685        msg = new MimeMessage(session, bais);
686        if (DUMP_MESSAGES) {
687          dumpMessage(msg);
688        }    
689        // message must be signed by MLA: S2(E1(S1(O))), checking signature S2
690        Object content = msg.getContent();
691        if ((content instanceof SignedContent == false)) {
692          throw new ESSException("Error: received message is not signed!");
693        }  
694        System.out.println("First layer of message is signed. Verifying signature.");
695        DataHandler dh = verify((SignedContent)content, signerCertificatesOfMLA_[0]);
696        // read MLExpansionHistory attribute, must contain one MLData entry
697        System.out.println("Reading MLExpansionHistory attribute.");
698        readMLExpansionHistory((SignedContent)content, 1);
699        // second layer must be encrypted
700        content = dh.getContent();
701        if ((content instanceof EncryptedContent == false)) {
702          throw new ESSException("Error: second layer of received message is not encrypted!");
703        }  
704        System.out.println("Second layer of message is encrypted. Trying to decrypt.");
705        dh = decrypt((EncryptedContent)content, recipientPrivateKey_, recipientCertificates_[0]);
706        // third layer must be signed, too
707        content = dh.getContent();
708        if ((content instanceof SignedContent == false)) {
709          throw new ESSException("Error: second layer of received message is not signed!");
710        }  
711        System.out.println("Third layer of message is signed. Verifying signature.");
712        dh = verify((SignedContent)content, signerCertificatesOfS1_[0]);
713        // check content
714        if (CryptoUtils.equalsBlock(dsBytes, getDataSource(dh)) == false) {
715          throw new Exception("Error: Original content changed!"); 
716        }  
717        dumpContent(dh);
718      }
719      
720      /**
721       * Tests the MLA behaviour for signed encrypted and signed signed message according to 
722       * sample 4.2.1,4) of <a href="https://www.rfc-editor.org/rfc/rfc2634.html" target = "_blank">RFC2634</a>:
723       * <pre>
724       * A message (S2(E1(S1(Original Content)))) is sent to the MLA in
725       * which S2 includes an MLExpansionHistory attribute. The MLA verifies
726       * the signature and fully processes the signedAttributes in S2. The
727       * MLA finds the mlExpansionHistory attribute in S2, so it decides
728       * that S2 is the "outer" signedData. The MLA remembers the
729       * signedAttributes included in S2 for later inclusion in the new
730       * outer signedData that it applies to the message. The MLA strips off
731       * S2. The MLA then expands the recipientInformation in E1 (this
732       * invalidates the signature in S2 which is why it was stripped). The
733       * nMLA calculates a new signedData layer, S3, resulting in the
734       * following message sent to the ML recipients: (S3(E1(S1(Original
735       * Content)))). The MLA includes in S3 the attributes from S2 (unless
736       * it specifically replaces an attribute value) including an updated
737       * mlExpansionHistory attribute.
738       * </pre>
739       * 
740       * @param session the current mail session
741       * @param mp the multipart content
742       * @param dsBytes the original content dataSorce bytes for comparison
743       * @param implicit whether implicit (content included) or explicit signing shall be used
744       *
745       * @throws Exception if an error coours
746       */
747      public void test_S2_E1_S1_O(Session session, Multipart mp, byte[] dsBytes, boolean implicit) throws Exception {
748        //  RFC2634, 4.2.1, 4) S2(E1(S1(Original Content))) ==> MLA(E1(S1(Original Content)))
749        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
750        ByteArrayInputStream bais;  // we read from a stream
751        
752        // 1. send signed and encrypted and signed message to MLA
753        System.out.println("1. Creating signed and encrypted/signed message and send it to MLA...");
754        Message msg = createMessage(session, senderAddress_, mlaAddress_);
755        msg.setSubject("RFC2634, 4.2.1, 4) S2(E1(S1(Original Content)))");
756        SignedContent sc = create_S2_E1_S1_0(mp, 
757                                             mp.getContentType(), 
758                                             implicit,
759                                             signerCertificatesOfS1_,
760                                             signerPrivateKeyOfS1_,
761                                             (AlgorithmID)AlgorithmID.sha256.clone(),
762                                             (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(),
763                                             null,
764                                             encryptionCertificatesOfMLA_[0],
765                                             (AlgorithmID)AlgorithmID.rsaEncryption.clone(),
766                                             (AlgorithmID)AlgorithmID.aes128_CBC.clone(),
767                                             128,
768                                             implicit,
769                                             signerCertificatesOfS2_,
770                                             signerPrivateKeyOfS2_,
771                                             (AlgorithmID)AlgorithmID.sha256.clone(),
772                                             (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(),
773                                             createMLExpansionHistory(signerCertificatesOfS2_[0], new Date(), null)); 
774        msg.setContent(sc, sc.getContentType());                                
775        sc.setHeaders(msg);
776        msg.saveChanges();
777        baos.reset();
778        msg.writeTo(baos);
779        // 2. MLA: receives messages, processes it and creates and sends a new signed message
780        System.out.println("2. MLA: Processing message...");
781        bais = new ByteArrayInputStream(baos.toByteArray());
782        msg = new MimeMessage(session, bais);
783        if (DUMP_MESSAGES) {
784          System.out.println("Received message:");  
785          dumpMessage(msg);
786        }  
787        sc = processMessageForMLA(msg, implicit, "S2_E1_S1_0");
788        System.out.println("MLA: Sending signed message to new recipient.");
789        msg = createMessage(session, mlaAddress_, recipientAddress_);
790        msg.setSubject("RFC2634, 4.2.1, 4) MLA(E1(S1(Original Content)))");
791        msg.setContent(sc, sc.getContentType());
792        sc.setHeaders(msg);
793        baos.reset();
794        msg.writeTo(baos);
795        // 3. final recipient: receives message from MLA, parses it
796        System.out.println("3. Final recipient: Parsing message received from MLA...");
797        bais = new ByteArrayInputStream(baos.toByteArray());
798        msg = new MimeMessage(session, bais);
799        if (DUMP_MESSAGES) {
800          dumpMessage(msg);
801        }    
802        // message must be signed by MLA: S3(E1(S1(O))), checking signature S3
803        Object content = msg.getContent();
804        if ((content instanceof SignedContent == false)) {
805          throw new ESSException("Error: received message is not signed!");
806        }  
807        System.out.println("First layer of message is signed. Verifying signature.");
808        DataHandler dh = verify((SignedContent)content, signerCertificatesOfMLA_[0]);
809        // read MLExpansionHistory attribute, must contain one MLData entry
810        System.out.println("Reading MLExpansionHistory attributes.");
811        readMLExpansionHistory((SignedContent)content, 2);
812        // second layer must be encrypted
813        content = dh.getContent();
814        if ((content instanceof EncryptedContent == false)) {
815          throw new ESSException("Error: second layer of received message is not encrypted!");
816        }  
817        System.out.println("Second layer of message is encrypted. Trying to decrypt.");
818        dh = decrypt((EncryptedContent)content, recipientPrivateKey_, recipientCertificates_[0]);
819        // third layer must be signed, too
820        content = dh.getContent();
821        if ((content instanceof SignedContent == false)) {
822          throw new ESSException("Error: second layer of received message is not signed!");
823        }  
824        System.out.println("Third layer of message is signed. Verifying signature.");
825        dh = verify((SignedContent)content, signerCertificatesOfS1_[0]);
826        // check content
827        if (CryptoUtils.equalsBlock(dsBytes, getDataSource(dh)) == false) {
828          throw new Exception("Error: Original content changed!"); 
829        }  
830        dumpContent(dh);
831      }
832      
833      /**
834       * Tests the MLA behaviour for double signed encrypted and signed signed message 
835       * according to  sample 4.2.1,5) of <a href="https://www.rfc-editor.org/rfc/rfc2634.html" target = "_blank">RFC2634</a>:
836       * <pre>
837       * A message (S3(S2(E1(S1(Original Content))))) is sent to the MLA in
838       * which none of the signedData layers include an MLExpansionHistory
839       * attribute. The MLA verifies the signature and fully processes the
840       * signedAttributes in S3 and S2. When the MLA encounters E1, then it
841       * decides that S2 is the "outer" signedData since S2 encapsulates E1.
842       * The MLA remembers the signedAttributes included in S2 for later
843       * inclusion in the new outer signedData that it applies to the
844       * message.  The MLA strips off S3 and S2. The MLA then expands the
845       * recipientInformation in E1 (this invalidates the signatures in S3
846       * and S2 which is why they were stripped). The MLA calculates a new
847       * signedData layer, S4, resulting in the following message sent to
848       * the ML recipients: (S4(E1(S1(Original Content)))). The MLA
849       * includes in S4 the attributes from S2 (unless it specifically
850       * replaces an attribute value) and includes a new
851       * mlExpansionHistory attribute.
852       * </pre>
853       * 
854       * @param session the current mail session
855       * @param mp the multipart content
856       * @param dsBytes the original content dataSorce bytes for comparison
857       * @param implicit whether implicit (content included) or explicit signing shall be used
858       * @param includeMLExpansionHistoryInS3 whether to include an MLExpansionHistory in the
859       *                                      the outermost signed layer (S3) of the original
860       *                                      message
861       *
862       * @throws Exception if an error coours
863       */
864      public void test_S3_S2_E1_S1_O(Session session, 
865                                     Multipart mp, 
866                                     byte[] dsBytes, 
867                                     boolean implicit,
868                                     boolean includeMLExpansionHistoryInS3) throws Exception {
869        //  RFC2634, 4.2.1, 5) S3(S2(E1(S1(Original Content)))) ==> MLA(E1(S1(Original Content)))
870        ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream
871        ByteArrayInputStream bais;  // we read from a stream
872        
873        // 1. send double signed and encrypted and signed message to MLA
874        System.out.println("1. Creating double signed and encrypted/signed message and send it to MLA...");
875        Message msg = createMessage(session, senderAddress_, mlaAddress_);
876        msg.setSubject("RFC2634, 4.2.1, 5) S3(S2(E1(S1(Original Content))))");
877        SignedContent sc = create_S3_S2_E1_S1_0(mp, 
878                                                mp.getContentType(), 
879                                                implicit,
880                                                signerCertificatesOfS1_,
881                                                signerPrivateKeyOfS1_,
882                                                (AlgorithmID)AlgorithmID.sha256.clone(),
883                                                (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(),
884                                                null,
885                                                encryptionCertificatesOfMLA_[0],
886                                                (AlgorithmID)AlgorithmID.rsaEncryption.clone(),
887                                                (AlgorithmID)AlgorithmID.aes128_CBC.clone(),
888                                                128,
889                                                implicit,
890                                                signerCertificatesOfS2_,
891                                                signerPrivateKeyOfS2_,
892                                                (AlgorithmID)AlgorithmID.sha256.clone(),
893                                                (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(),
894                                                null,
895                                                implicit,
896                                                signerCertificatesOfS3_,
897                                                signerPrivateKeyOfS3_,
898                                                (AlgorithmID)AlgorithmID.sha256.clone(),
899                                                (AlgorithmID)AlgorithmID.rsaEncryption.clone(),
900                                                (includeMLExpansionHistoryInS3 ?
901                                                createMLExpansionHistory(signerCertificatesOfS3_[0], new Date(), null) :
902                                                null));
903        msg.setContent(sc, sc.getContentType());                                
904        sc.setHeaders(msg);
905        msg.saveChanges();
906        baos.reset();
907        msg.writeTo(baos);
908        // 2. MLA: receives messages, processes it and creates and sends a new signed message
909        System.out.println("2. MLA: Processing message...");
910        bais = new ByteArrayInputStream(baos.toByteArray());
911        msg = new MimeMessage(session, bais);
912        if (DUMP_MESSAGES) {
913          System.out.println("Received message:");  
914          dumpMessage(msg);
915        }  
916        sc = processMessageForMLA(msg, implicit, "S3_S2_E1_S1_0");
917        System.out.println("MLA: Sending signed message to new recipient.");
918        msg = createMessage(session, mlaAddress_, recipientAddress_);
919        msg.setSubject("RFC2634, 4.2.1, 5) MLA(E1(S1(Original Content)))");
920        msg.setContent(sc, sc.getContentType());
921        sc.setHeaders(msg);
922        baos.reset();
923        msg.writeTo(baos);
924        // 3. final recipient: receives message from MLA, parses it
925        System.out.println("3. Final recipient: Parsing message received from MLA...");
926        bais = new ByteArrayInputStream(baos.toByteArray());
927        msg = new MimeMessage(session, bais);
928        if (DUMP_MESSAGES) {
929          dumpMessage(msg);
930        }    
931        // message must be signed by MLA: S4(E1(S1(O))), checking signature S4
932        Object content = msg.getContent();
933        if ((content instanceof SignedContent == false)) {
934          throw new ESSException("Error: received message is not signed!");
935        }  
936        System.out.println("First layer of message is signed. Verifying signature.");
937        DataHandler dh = verify((SignedContent)content, signerCertificatesOfMLA_[0]);
938        // read MLExpansionHistory attribute, must contain one MLData entry
939        System.out.println("Reading MLExpansionHistory attributes.");
940        readMLExpansionHistory((SignedContent)content, includeMLExpansionHistoryInS3 ? 2 : 1);
941        // second layer must be encrypted
942        content = dh.getContent();
943        if ((content instanceof EncryptedContent == false)) {
944          throw new ESSException("Error: second layer of received message is not encrypted!");
945        }  
946        System.out.println("Second layer of message is encrypted. Trying to decrypt.");
947        dh = decrypt((EncryptedContent)content, recipientPrivateKey_, recipientCertificates_[0]);
948        // third layer must be signed, too
949        content = dh.getContent();
950        if ((content instanceof SignedContent == false)) {
951          throw new ESSException("Error: second layer of received message is not signed!");
952        }  
953        System.out.println("Third layer of message is signed. Verifying signature.");
954        dh = verify((SignedContent)content, signerCertificatesOfS1_[0]);
955        // check content
956        if (CryptoUtils.equalsBlock(dsBytes, getDataSource(dh)) == false) {
957          throw new Exception("Error: Original content changed!"); 
958        }  
959        dumpContent(dh);
960      }
961    
962      /**
963       * Creates a new MimeMessage without content and sets the From:, To:, and Date: headers.
964       * 
965       * @param session the current mail session
966       * @param from the address of the sender of the message
967       * @param to the address of the indented message recipient
968       * @return the new created MimeMessage
969       * @throws MessagingException if an error occurs when setting the message headers
970       */
971      public Message createMessage(Session session, String from, String to) throws MessagingException {
972        MimeMessage msg = new MimeMessage(session);
973        msg.setFrom(new InternetAddress(from));
974            msg.setRecipients(Message.RecipientType.TO,     InternetAddress.parse(to, false));
975            msg.setSentDate(new Date());
976        return msg;
977      }
978      
979      /**
980       * Creates a SignedContent.
981       *
982       * @param content the content to be signed
983       * @param contentType the MIME type of the content
984       * @param implicit whether to create an implicit (application/pkcs7-mime) or 
985       *                 explicit (multipart/signed) message
986       * @param signerCertificates the certificate chain of the signer
987       * @param signerPrivateKey the private key to be used for signing the content
988       * @param digestAlg the algorithm to be used for digest calculation
989       * @param signatureAlg the algorithm to be used for signature calculation
990       * @param mlExpansionHistory MLExpansionHistory attribute to be added; maybe null
991       *
992       * @return the SignedContent
993       *
994       * @throws MessagingException if a problem occurs when creating the SignedContent
995       */
996      public SignedContent createSignedContent(Object content, 
997                                               String contentType, 
998                                               boolean implicit,
999                                               X509Certificate[] signerCertificates,
1000                                               PrivateKey signerPrivateKey,
1001                                               AlgorithmID digestAlg,
1002                                               AlgorithmID signatureAlg,
1003                                               MLExpansionHistory mlExpansionHistory)
1004        throws MessagingException {
1005    
1006        SignedContent sc = new SignedContent(implicit);
1007        sc.setContent(content, contentType);
1008        sc.setCertificates(signerCertificates);
1009        try {
1010          // create a set of standard attributes
1011          Attributes attributes = SMimeUtil.makeStandardAttributes();
1012          if (mlExpansionHistory != null) {
1013            attributes.addAttribute(new Attribute(mlExpansionHistory));
1014          }
1015          sc.addSigner(signerPrivateKey, signerCertificates[0], digestAlg, signatureAlg, attributes.toArray());
1016        } catch (NoSuchAlgorithmException ex) {
1017          throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex);
1018        } catch (CodingException ex) {
1019          throw new MessagingException("Error in attribute encoding: " + ex.getMessage());   
1020        } catch (SMimeException ex) {
1021          throw new MessagingException("Error adding attributes: " + ex.toString());   
1022        }    
1023    
1024        return sc;
1025      }
1026      
1027      /**
1028       * Creates an EncryptedContent.
1029       *
1030       * @param content the content to be encrypted
1031       * @param contentType the MIME type of the content
1032       * @param recipientCertificate the encryption certificate of the recipient
1033       * @param cekEncrAlg the algorithm to be used for encrypting the symmetric content encryption key
1034       *                   (e.g. AlgorithmID.rsaEncryption)
1035       * @param contentEncrAlg the symmetric key to be used for encrypting the content, e.g. AlgorithmID.aes256_CBC
1036       * @param cekLength the length of the temporary content encryption key to be generated (e.g. 256)
1037       *
1038       * @return the EncryptedContent
1039       *
1040       * @throws MessagingException if a problem occurs when creating the EncryptedContent
1041       */
1042      public EncryptedContent createEncryptedContent(Object content, 
1043                                                     String contentType,
1044                                                     X509Certificate recipientCertificate,
1045                                                     AlgorithmID cekEncrAlg,
1046                                                     AlgorithmID contentEncrAlg,
1047                                                     int cekLength) throws MessagingException {
1048    
1049        EncryptedContent ec = new EncryptedContent();
1050        ec.setContent(content, contentType);
1051        // encrypt for the recipient
1052        ec.addRecipient(recipientCertificate, cekEncrAlg);
1053        try {
1054          ec.setEncryptionAlgorithm(contentEncrAlg, cekLength);
1055        } catch (NoSuchAlgorithmException ex) {
1056          throw new MessagingException("Content encryption algorithm not supported: " + ex.getMessage());   
1057        }   
1058    
1059        return ec;
1060      }
1061      
1062      /**
1063       * Signs the given content.
1064       *
1065       * @param content the content to be signed
1066       * @param contentType the MIME type of the content
1067       * @param implicitS1 whether to create an implicit (application/pkcs7-mime) or 
1068       *                 explicit (multipart/signed) message
1069       * @param signerCertificatesS1 the certificate chain of the signer
1070       * @param signerPrivateKeyS1 the private key to be used for signing the content
1071       * @param digestAlgS1 the algorithm to be used for digest calculation
1072       * @param signatureAlgS1 the algorithm to be used for signature calculation
1073       * @param mlExpansionHistoryS1 MLExpansionHistory attribute to be added; maybe null
1074       *
1075       * @return the SignedContent
1076       *
1077       * @throws MessagingException if a problem occurs when creating the SignedContent
1078       */
1079      public SignedContent create_S1_O(Object content, 
1080                                       String contentType, 
1081                                       boolean implicitS1,
1082                                       X509Certificate[] signerCertificatesS1,
1083                                       PrivateKey signerPrivateKeyS1,
1084                                       AlgorithmID digestAlgS1,
1085                                       AlgorithmID signatureAlgS1,
1086                                       MLExpansionHistory mlExpansionHistoryS1) 
1087        throws MessagingException {
1088                                        
1089        return createSignedContent(content, 
1090                                   contentType, 
1091                                   implicitS1, 
1092                                   signerCertificatesS1, 
1093                                   signerPrivateKeyS1, 
1094                                   digestAlgS1, 
1095                                   signatureAlgS1,
1096                                   mlExpansionHistoryS1);                                  
1097      }                                    
1098      
1099      /**
1100       * Triple-signs the given content.
1101       *
1102       * @param content the content to be signed
1103       * @param contentType the MIME type of the content
1104       * @param implicitS1 if the first signature shall be implicit (application/pkcs7-mime) or 
1105       *                   explicit (multipart/signed) 
1106       * @param signerCertificatesS1 the certificate chain of the first signer
1107       * @param signerPrivateKeyS1 the private key of the first signer
1108       * @param digestAlgS1 the digest algorithm to be used for digest calculation by the innermost SignedContent
1109       * @param signatureAlgS1 the algorithm to be used for signature calculation by the innermost SignedContent
1110       * @param mlExpansionHistoryS1 MLExpansionHistory attribute to be added to the innermost SignedContent; maybe null
1111       * @param implicitS2 if the second signature shall be implicit (application/pkcs7-mime) or 
1112       *                   explicit (multipart/signed) 
1113       * @param signerCertificatesS2 the certificate chain of the second signer
1114       * @param signerPrivateKeyS2 the private key of the second signer
1115       * @param digestAlgS2 the digest algorithm to be used for digest calculation by the middle SignedContent
1116       * @param signatureAlgS2 the algorithm to be used for signature calculation by the middle SignedContent
1117       * @param mlExpansionHistoryS2 MLExpansionHistory attribute to be added to the middle SignedContent; maybe null
1118       * @param implicitS3 if the first signature shall be implicit (application/pkcs7-mime) or 
1119       *                   explicit (multipart/signed) 
1120       * @param signerCertificatesS3 the certificate chain of the third signer
1121       * @param signerPrivateKeyS3 the private key of the third signer
1122       * @param digestAlgS3 the digest algorithm to be used for digest calculation by the outermost SignedContent
1123       * @param signatureAlgS3 the algorithm to be used for signature calculation by the outermost SignedContent
1124       * @param mlExpansionHistoryS3 MLExpansionHistory attribute to be added for the outermost SignedContent; maybe null
1125       *
1126       * @return the SignedContent
1127       *
1128       * @throws MessagingException if a problem occurs when creating the SignedContent
1129       */
1130      public SignedContent create_S3_S2_S1_O(Object content, 
1131                                             String contentType, 
1132                                             boolean implicitS1,
1133                                             X509Certificate[] signerCertificatesS1,
1134                                             PrivateKey signerPrivateKeyS1,
1135                                             AlgorithmID digestAlgS1,
1136                                             AlgorithmID signatureAlgS1,
1137                                             MLExpansionHistory mlExpansionHistoryS1,
1138                                             boolean implicitS2,
1139                                             X509Certificate[] signerCertificatesS2,
1140                                             PrivateKey signerPrivateKeyS2,
1141                                             AlgorithmID digestAlgS2,
1142                                             AlgorithmID signatureAlgS2,
1143                                             MLExpansionHistory mlExpansionHistoryS2,
1144                                             boolean implicitS3,
1145                                             X509Certificate[] signerCertificatesS3,
1146                                             PrivateKey signerPrivateKeyS3,
1147                                             AlgorithmID digestAlgS3,
1148                                             AlgorithmID signatureAlgS3,
1149                                             MLExpansionHistory mlExpansionHistoryS3) 
1150         throws MessagingException {
1151         SignedContent s1 = create_S1_O(content, contentType, 
1152                                        implicitS1, signerCertificatesS1, signerPrivateKeyS1, digestAlgS1, signatureAlgS1, mlExpansionHistoryS1); 
1153         SignedContent s2 = createSignedContent(s1, s1.getContentType(), 
1154                                                implicitS2, signerCertificatesS2, signerPrivateKeyS2, digestAlgS2, signatureAlgS2, mlExpansionHistoryS2);                            
1155         return createSignedContent(s2, s2.getContentType(), 
1156                                    implicitS3, signerCertificatesS3, signerPrivateKeyS3, digestAlgS3, signatureAlgS3, mlExpansionHistoryS3);                                                          
1157      }  
1158      
1159      /**
1160       * Encrypts and signs the given content.
1161       *
1162       * @param content the content to be signed
1163       * @param contentType the MIME type of the content
1164       * @param implicitS1 whether to create an implicit (application/pkcs7-mime) or 
1165       *                 explicit (multipart/signed) message
1166       * @param signerCertificatesS1 the certificate chain of the signer
1167       * @param signerPrivateKeyS1 the private key to be used for signing the content
1168       * @param digestAlgS1 the algorithm to be used for digest calculation
1169       * @param signatureAlgS1 the algorithm to be used for signature calculation
1170       * @param mlExpansionHistoryS1 MLExpansionHistory attribute to be added; maybe null
1171       * @param recipientCertificate the encryption certificate of the recipient
1172       * @param cekEncrAlg the algorithm to be used for encrypting the symmetric content encryption key
1173       *                   (e.g. AlgorithmID.rsaEncryption)
1174       * @param contentEncrAlg the symmetric key to be used for encrypting the content, e.g. AlgorithmID.aes256_CBC
1175       * @param cekLength the length of the temporary content encryption key to be generated (e.g. 256)
1176       *
1177       * @return the signed and encrypted message
1178       *
1179       * @throws MessagingException if a problem occurs when creating the SignedContent or EncryptedContent
1180       */
1181      public EncryptedContent create_E1_S1_O(Object content, 
1182                                             String contentType, 
1183                                             boolean implicitS1,
1184                                             X509Certificate[] signerCertificatesS1,
1185                                             PrivateKey signerPrivateKeyS1,
1186                                             AlgorithmID digestAlgS1,
1187                                             AlgorithmID signatureAlgS1,
1188                                             MLExpansionHistory mlExpansionHistoryS1,
1189                                             X509Certificate recipientCertificate,
1190                                             AlgorithmID cekEncrAlg,
1191                                             AlgorithmID contentEncrAlg,
1192                                             int cekLength) 
1193         throws MessagingException {
1194            
1195         SignedContent s1 = create_S1_O(content, contentType, 
1196                                        implicitS1, signerCertificatesS1, signerPrivateKeyS1, digestAlgS1, signatureAlgS1, mlExpansionHistoryS1); 
1197         return createEncryptedContent(s1, s1.getContentType(), 
1198                                       recipientCertificate, cekEncrAlg, contentEncrAlg, cekLength);                                       
1199      }    
1200      
1201      
1202      /**
1203       * Signs and encrypts and signs the given content.
1204       *
1205       * @param content the content to be signed
1206       * @param contentType the MIME type of the content
1207       * @param implicitS1 if the first signature shall be implicit (application/pkcs7-mime) or 
1208       *                   explicit (multipart/signed) 
1209       * @param signerCertificatesS1 the certificate chain of the first signer
1210       * @param signerPrivateKeyS1 the private key of the first signer
1211       * @param digestAlgS1 the digest algorithm to be used for digest calculation by the innermost SignedContent
1212       * @param signatureAlgS1 the algorithm to be used for signature calculation by the innermost SignedContent
1213       * @param mlExpansionHistoryS1 MLExpansionHistory attribute to be added to the innermost SignedContent; maybe null
1214       * @param recipientCertificate the encryption certificate of the recipient
1215       * @param cekEncrAlg the algorithm to be used for encrypting the symmetric content encryption key
1216       *                   (e.g. AlgorithmID.rsaEncryption)
1217       * @param contentEncrAlg the symmetric key to be used for encrypting the content, e.g. AlgorithmID.aes256_CBC
1218       * @param cekLength the length of the temporary content encryption key to be generated (e.g. 256)
1219       * @param implicitS2 if the second signature shall be implicit (application/pkcs7-mime) or 
1220       *                   explicit (multipart/signed) 
1221       * @param signerCertificatesS2 the certificate chain of the second signer
1222       * @param signerPrivateKeyS2 the private key of the second signer
1223       * @param digestAlgS2 the digest algorithm to be used for digest calculation by the outer SignedContent
1224       * @param signatureAlgS2 the algorithm to be used for signature calculation by the outer SignedContent
1225       * @param mlExpansionHistoryS2 MLExpansionHistory attribute to be added to the outer SignedContent; maybe null
1226       *
1227       * @return the signed and encrypted and signed message
1228       *
1229       * @throws MessagingException if a problem occurs when creating a SignedContent or EncryptedContent
1230       */
1231      public SignedContent create_S2_E1_S1_0(Object content, 
1232                                             String contentType, 
1233                                             boolean implicitS1,
1234                                             X509Certificate[] signerCertificatesS1,
1235                                             PrivateKey signerPrivateKeyS1,
1236                                             AlgorithmID digestAlgS1,
1237                                             AlgorithmID signatureAlgS1,
1238                                             MLExpansionHistory mlExpansionHistoryS1,
1239                                             X509Certificate recipientCertificate,
1240                                             AlgorithmID cekEncrAlg,
1241                                             AlgorithmID contentEncrAlg,
1242                                             int cekLength,
1243                                             boolean implicitS2,
1244                                             X509Certificate[] signerCertificatesS2,
1245                                             PrivateKey signerPrivateKeyS2,
1246                                             AlgorithmID digestAlgS2,
1247                                             AlgorithmID signatureAlgS2,
1248                                             MLExpansionHistory mlExpansionHistoryS2) 
1249        throws MessagingException {
1250            
1251        EncryptedContent e1 = create_E1_S1_O(content, 
1252                                             contentType, 
1253                                             implicitS1,
1254                                             signerCertificatesS1,
1255                                             signerPrivateKeyS1,
1256                                             digestAlgS1,
1257                                             signatureAlgS1,
1258                                             mlExpansionHistoryS1,
1259                                             recipientCertificate,
1260                                             cekEncrAlg,
1261                                             contentEncrAlg,
1262                                             cekLength);
1263        return createSignedContent(e1, e1.getContentType(), 
1264                                   implicitS2, signerCertificatesS2, signerPrivateKeyS2, digestAlgS2, signatureAlgS2, mlExpansionHistoryS2);                                     
1265      }      
1266      
1267      /**
1268       * Signs and encrypts and double-signs the given content.
1269       *
1270       * @param content the content to be signed
1271       * @param contentType the MIME type of the content
1272       * @param implicitS1 if the first signature shall be implicit (application/pkcs7-mime) or 
1273       *                   explicit (multipart/signed) 
1274       * @param signerCertificatesS1 the certificate chain of the first signer
1275       * @param signerPrivateKeyS1 the private key of the first signer
1276       * @param digestAlgS1 the digest algorithm to be used for digest calculation by the innermost SignedContent
1277       * @param signatureAlgS1 the algorithm to be used for signature calculation by the innermost SignedContent
1278       * @param mlExpansionHistoryS1 MLExpansionHistory attribute to be added to the innermost SignedContent; maybe null
1279       * @param recipientCertificate the encryption certificate of the recipient
1280       * @param cekEncrAlg the algorithm to be used for encrypting the symmetric content encryption key
1281       *                   (e.g. AlgorithmID.rsaEncryption)
1282       * @param contentEncrAlg the symmetric key to be used for encrypting the content, e.g. AlgorithmID.aes256_CBC
1283       * @param cekLength the length of the temporary content encryption key to be generated (e.g. 256)
1284       * @param implicitS2 if the second signature shall be implicit (application/pkcs7-mime) or 
1285       *                   explicit (multipart/signed) 
1286       * @param signerCertificatesS2 the certificate chain of the second signer
1287       * @param signerPrivateKeyS2 the private key of the second signer
1288       * @param digestAlgS2 the digest algorithm to be used for digest calculation by the middle SignedContent
1289       * @param signatureAlgS2 the algorithm to be used for signature calculation by the middle SignedContent
1290       * @param mlExpansionHistoryS2 MLExpansionHistory attribute to be added to the middle SignedContent; maybe null
1291       * @param implicitS3 if the first signature shall be implicit (application/pkcs7-mime) or 
1292       *                   explicit (multipart/signed) 
1293       * @param signerCertificatesS3 the certificate chain of the third signer
1294       * @param signerPrivateKeyS3 the private key of the third signer
1295       * @param digestAlgS3 the digest algorithm to be used for digest calculation by the outermost SignedContent
1296       * @param signatureAlgS3 the algorithm to be used for signature calculation by the outermost SignedContent
1297       * @param mlExpansionHistoryS3 MLExpansionHistory attribute to be added for the outermost SignedContent; maybe null
1298       *
1299       * @return the signed and encrypted and double-signed message
1300       *
1301       * @throws MessagingException if a problem occurs when creating a SignedContent or EncryptedContent
1302       */
1303      public SignedContent create_S3_S2_E1_S1_0(Object content, 
1304                                               String contentType, 
1305                                               boolean implicitS1,
1306                                               X509Certificate[] signerCertificatesS1,
1307                                               PrivateKey signerPrivateKeyS1,
1308                                               AlgorithmID digestAlgS1,
1309                                               AlgorithmID signatureAlgS1,
1310                                               MLExpansionHistory mlExpansionHistoryS1,
1311                                               X509Certificate recipientCertificate,
1312                                               AlgorithmID cekEncrAlg,
1313                                               AlgorithmID contentEncrAlg,
1314                                               int cekLength,
1315                                               boolean implicitS2,
1316                                               X509Certificate[] signerCertificatesS2,
1317                                               PrivateKey signerPrivateKeyS2,
1318                                               AlgorithmID digestAlgS2,
1319                                               AlgorithmID signatureAlgS2,
1320                                               MLExpansionHistory mlExpansionHistoryS2,
1321                                               boolean implicitS3,
1322                                               X509Certificate[] signerCertificatesS3,
1323                                               PrivateKey signerPrivateKeyS3,
1324                                               AlgorithmID digestAlgS3,
1325                                               AlgorithmID signatureAlgS3,
1326                                               MLExpansionHistory mlExpansionHistoryS3) 
1327        throws MessagingException {
1328            
1329        SignedContent s2 = create_S2_E1_S1_0(content, 
1330                                             contentType, 
1331                                             implicitS1,
1332                                             signerCertificatesS1,
1333                                             signerPrivateKeyS1,
1334                                             digestAlgS1,
1335                                             signatureAlgS1,
1336                                             mlExpansionHistoryS1,
1337                                             recipientCertificate,
1338                                             cekEncrAlg,
1339                                             contentEncrAlg,
1340                                             cekLength,
1341                                             implicitS2,
1342                                             signerCertificatesS2,
1343                                             signerPrivateKeyS2,
1344                                             digestAlgS2,
1345                                             signatureAlgS2,
1346                                             mlExpansionHistoryS2) ;
1347        
1348        return createSignedContent(s2, s2.getContentType(), 
1349                                   implicitS3, signerCertificatesS3, signerPrivateKeyS3, digestAlgS3, signatureAlgS3, mlExpansionHistoryS3);                                     
1350      }      
1351      
1352      /**
1353       * Decrypts the encrypted content with the given key of the identified recipient.
1354       * 
1355       * @param ec the EncryptedContent to be decrypted
1356       * @param privateKey the private key to be used to decrypt the encrypted content
1357       * @param certificate the certificate identifying the recipient for which to decrypt the encrypted content
1358       *
1359       * @return the DataHandler holding the recovered (decrypted) content
1360       *
1361       * @throws SMimeException if an error occurs while decrypting the content
1362       */
1363      public DataHandler decrypt(EncryptedContent ec, PrivateKey privateKey, X509Certificate certificate)
1364        throws SMimeException {
1365        try {    
1366          ec.decryptSymmetricKey(privateKey, certificate);
1367          return ec.getDataHandler();
1368        } catch (Exception ex) {
1369          throw new SMimeException(ex.toString());   
1370        }    
1371      }  
1372      
1373      /**
1374       * Verifies the signature of the given SignedContent and returns the inherent content data.
1375       * 
1376       * @param sc the SignedContent to be verified
1377       * @param signerCert the certificate of the signer (to check if the message has been signed
1378       *                                                  by the expected entity)
1379       * @return the inherent content data
1380       * @throws CMSSignatureException if the signature is invalid
1381       * @throws ESSException if an error occurs when accessing the inherent content or
1382       *                         the message has been signed by an unexpected entity
1383       * @throws MessagingException if an error occurs when accessing the content
1384        */
1385      public DataHandler verify(SignedContent sc, X509Certificate signerCert) 
1386        throws CMSSignatureException, MessagingException, ESSException {
1387            
1388        X509Certificate signer = sc.verify(); 
1389        System.out.println("Signature ok from: "+signer.getSubjectDN());
1390        if (signer.equals(signerCert) == false) {
1391          throw new ESSException("Error: message signed by wrong entity (" + signer.getSubjectDN() + ").\nExpected "
1392                                  + signerCert.getSubjectDN());  
1393        }    
1394        return sc.getDataHandler();
1395      }  
1396      
1397      /**
1398       * Dumps the content of the original multipart message.
1399       * 
1400       * @param dh the dataHandler supplying the content of the original message
1401       * @throws IOException if an I/O error occurs while dumping the content
1402       * @throws MessagingException if an error occurs while reading the body parts of the message
1403       */
1404      public void dumpContent(DataHandler dh) throws IOException, MessagingException {
1405        Multipart mp = (Multipart)dh.getContent(); 
1406        System.out.println("Content is multipart (" + mp.getContentType() + ").");
1407        BodyPart bp1 = mp.getBodyPart(0);
1408        System.out.println("Content of first bodypart  (" + bp1.getContentType() + "):");
1409        System.out.println(bp1.getContent());
1410        BodyPart bp2 = mp.getBodyPart(1);
1411        System.out.println("Content of second bodypart  (" + bp2.getContentType() + "):");
1412        System.out.println(bp2.getContent());
1413        
1414      }  
1415      
1416      public SignedContent processMessageForMLA(Message msg, boolean implicit, String debugID) throws ESSLayerException, ESSException {
1417        
1418        // resolve the message into its layers
1419        ESSLayers layers = mla_.resolve(msg, debugID);
1420        try {
1421          return mla_.createSignedContent(signerPrivateKeyOfMLA_,
1422                                          new Date(),
1423                                          signerCertificatesOfMLA_[0], 
1424                                          signerCertificatesOfMLA_, 
1425                                          (AlgorithmID)AlgorithmID.sha256.clone(), 
1426                                          (AlgorithmID)AlgorithmID.rsaEncryption.clone(),
1427                                          encryptionCertificatesOfMLA_[0],
1428                                          true, 
1429                                          implicit,
1430                                          layers);
1431        } catch (Exception ex) {
1432          throw new ESSException("Error signing content: " + ex.toString()); 
1433        }  
1434      }  
1435      
1436      /**
1437       * Gets the data source encoding from the given data handler.
1438       *
1439       * @param dh the data handler from which to get the data source
1440       * 
1441       * @return the dataSource encoding; used for comparison
1442       *
1443       * @throws IOExceptio if an error occurs when reading the datasource
1444       */
1445      private byte[] getDataSource(DataHandler dh) throws IOException {
1446        DataSource ds = dh.getDataSource();
1447        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1448        Utils.copyStream(ds.getInputStream(), baos, null);
1449        return baos.toByteArray();
1450      }  
1451    
1452      
1453      
1454      /**
1455       * Creates a MLExpansionHistory containing only one MLData for
1456       * the given MLA with given expansion time and MLReceiptPolicy.
1457       *
1458       * @param mlaCertificate the certificate of the MLA from which to create the
1459       *        MLData EntityIdentiifier of type IssuerAndSerialNumber
1460       * @param expansionTime the expansion time
1461       * @param mlReceiptPolicy the MLReceiptPolicy; may be null
1462       *
1463       * @return the newly created MLExpansionHistory
1464       */
1465      public static MLExpansionHistory createMLExpansionHistory(X509Certificate mlaCertificate,
1466                                                         Date expansionTime,
1467                                                         MLReceiptPolicy mlReceiptPolicy) {
1468        
1469        IssuerAndSerialNumber ias = new IssuerAndSerialNumber(mlaCertificate);
1470        MLData mlData = new MLData(new EntityIdentifier(ias), expansionTime); 
1471        mlData.setMLReceiptPolicy(mlReceiptPolicy);
1472        return new MLExpansionHistory(mlData);
1473      }                                                       
1474      
1475      /**
1476       * Reads the MLExpansionHistory attribute from the given signed data and dumps the 
1477       * included MLData structures.
1478       *
1479       * @param signedContent the (MLA created) SignedContent to be parsed for the MLExpansionHistory
1480       *                      attribute
1481       * @param count the (expected) number of MLData entries included in the MLExpansionHistory attribute
1482       *
1483       * @throws Exception if an error occurs when parsing the MLExpansionHistory attribute, or if
1484       *                      no MLExpansionHistory attribute is inlcuded or if the MLExpansionHistory
1485       *                      does contain an unexpected number of MLData entries
1486       */
1487      public static void readMLExpansionHistory(SignedContent signedContent, int count) throws Exception {
1488        SignerInfo signerInfo = signedContent.getSignerInfos()[0]; 
1489        MLExpansionHistory mlExpansionHistory = (MLExpansionHistory)signerInfo.getSignedAttributeValue(MLExpansionHistory.oid);
1490        if (mlExpansionHistory == null) {
1491          throw new Exception("Missing MLExpansionHistory attribute");   
1492        }    
1493        int size = mlExpansionHistory.countMLDataEntries();
1494        if (count != size) {
1495          throw new Exception("Invalid number (" + size + ") of MLData entries. Expected " + count);   
1496        }    
1497        System.out.println(mlExpansionHistory.toString(true));
1498      }  
1499      
1500      /** 
1501       * Prints a dump of the given message to System.out.
1502       *
1503       * @param msg the message to be dumped to System.out
1504       */
1505      private static void dumpMessage(Message msg) throws IOException {
1506        System.out.println("******************************************************************");
1507        System.out.println("Message dump: \n");
1508        try {
1509          msg.writeTo(System.out);
1510        } catch (MessagingException ex) {
1511          throw new IOException(ex.getMessage());   
1512        }    
1513        System.out.println("\n******************************************************************");
1514      }  
1515      
1516      /**
1517       * Main method.
1518       */
1519      public static void main(String[] argv) throws Exception {
1520        try {
1521          DemoSMimeUtil.initDemos();
1522          (new MLADemo()).start();
1523        } catch (Exception ex) {
1524          ex.printStackTrace();   
1525        }       
1526        DemoUtil.waitKey();
1527      }
1528    }