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