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 < 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 }