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.// Copyright (C) 2002 IAIK 057 // https://sic.tech 058 // 059 // Copyright (C) 2003 - 2025 Stiftung Secure Information and 060 // Communication Technologies SIC 061 // https://sic.tech 062 // 063 // All rights reserved. 064 // 065 // This source is provided for inspection purposes and recompilation only, 066 // unless specified differently in a contract with IAIK. This source has to 067 // be kept in strict confidence and must not be disclosed to any third party 068 // under any circumstances. Redistribution in source and binary forms, with 069 // or without modification, are <not> permitted in any case! 070 // 071 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 072 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 073 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 074 // ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 075 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 076 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 077 // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 078 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 079 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 080 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 081 // SUCH DAMAGE. 082 // 083 // $Header: /IAIK-CMS/current/src/demo/smime/ess/SignedReceiptDemo.java 39 12.02.25 17:59 Dbratko $ 084 // $Revision: 39 $ 085 // 086 087 package demo.smime.ess; 088 089 import iaik.asn1.structures.AlgorithmID; 090 import iaik.asn1.structures.Attribute; 091 import iaik.cms.IssuerAndSerialNumber; 092 import iaik.cms.SignerInfo; 093 import iaik.smime.SMimeSignerInfo; 094 import iaik.smime.SignedContent; 095 import iaik.smime.ess.ContentIdentifier; 096 import iaik.smime.ess.ESSException; 097 import iaik.smime.ess.EntityIdentifier; 098 import iaik.smime.ess.MLData; 099 import iaik.smime.ess.MLExpansionHistory; 100 import iaik.smime.ess.MLReceiptPolicy; 101 import iaik.smime.ess.Receipt; 102 import iaik.smime.ess.ReceiptContent; 103 import iaik.smime.ess.ReceiptRequest; 104 import iaik.smime.ess.ReceiptsFrom; 105 import iaik.smime.ess.utils.SenderAndReceiptContentDigest; 106 import iaik.smime.ess.utils.SignedReceipt; 107 import iaik.x509.X509Certificate; 108 109 import java.io.ByteArrayInputStream; 110 import java.io.ByteArrayOutputStream; 111 import java.io.IOException; 112 import java.io.OutputStream; 113 import java.security.NoSuchAlgorithmException; 114 import java.security.PrivateKey; 115 import java.security.PublicKey; 116 import java.security.SignatureException; 117 import java.util.Date; 118 119 import javax.mail.Message; 120 import javax.mail.MessagingException; 121 import javax.mail.Session; 122 import javax.mail.internet.InternetAddress; 123 import javax.mail.internet.MimeMessage; 124 125 import demo.DemoSMimeUtil; 126 import demo.DemoUtil; 127 import demo.keystore.CMSKeyStore; 128 129 130 /** 131 * An <a href="https://www.rfc-editor.org/rfc/rfc2634.html" target = "_blank">RFC2634</a> ESS ReceiptRequest -- SignedReceipt demo. 132 * <p> 133 * This demo creates a message with a {@link iaik.smime.ess.ReceiptRequest 134 * ReceiptRequest} attribute and "sends" it to some intended recipient. 135 * The recipient then "sends" a signed receipt message back to the 136 * original sender who finally validates the signed receipt. 137 * A further test run adds a MLA layer with a {@link iaik.smime.ess.MLExpansionHistory 138 * MLExpansionHistory} attribute, 139 * that supersedes the original receipt request. 140 * <p> 141 * To run this demo the following packages are required: 142 * <ul> 143 * <li> 144 * <code>iaik_cms.jar</code> 145 * </li> 146 * <li> 147 * <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>). 148 * </li> 149 * <li> 150 * <code>mail.jar</code> (<a href="http://www.oracle.com/technetwork/java/javamail/index.html" target="_blank">JavaMail API</a>). 151 * </li> 152 * <li> 153 * <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). 154 * </li> 155 * </ul> 156 * 157 * @see iaik.smime.ess.ReceiptRequest 158 * @see iaik.smime.ess.Receipt 159 * @see iaik.smime.ess.MLExpansionHistory 160 * @see iaik.smime.ess.MLData 161 * @see iaik.smime.ess.MLReceiptPolicy 162 * @see iaik.smime.ess.utils.SignedReceipt 163 */ 164 public class SignedReceiptDemo { 165 166 // whether to dump all generates test messages to System.out 167 final static boolean DUMP_MESSAGES = false; 168 169 // sender (sends a receipt request message) 170 String senderName_ = "IAIK Demo Sender"; 171 // recipient (receives a receipt request and sends a signed receipt) 172 String recipientName_ = "IAIK Demo Recipient"; 173 // an mail list agent 174 String mlaName_ = "IAIK Demo ML Agent"; 175 // we use the same email address for all parties 176 String senderAddress_ = "\""+senderName_+"\" <smimetest@iaik.at>"; 177 String recipientAddress_ = "\""+recipientName_+"\" <smimetest@iaik.at>"; 178 String mlaAddress_ = "\""+mlaName_+"\" <smimetest@iaik.tugraz.at>"; 179 180 String host_ = "mailhost"; // name of the mailhost 181 182 X509Certificate[] signerCertificates_; // signer certificate list 183 X509Certificate signerCertificate_; // certificate of the signer/sender 184 X509Certificate encryptionCertOfSigner_; // signer uses different certificate for encryption 185 PrivateKey signerPrivateKey_; // private key of the signer/sender 186 187 X509Certificate[] recipientCertificates_; // recipient certificate list 188 X509Certificate recipientCertificate_; // certificate of the recipient 189 X509Certificate encryptionCertOfRecipient_; // recipient uses different certificate for encryption 190 PrivateKey recipientPrivateKey_; // private key of the recipient 191 192 X509Certificate[] signerCertificatesOfMLA_; // signer certificates of MLA 193 PrivateKey signerPrivateKeyOfMLA_; // signer private key of MLA 194 195 196 /** 197 * Empty default constructor. Reads all required keys and certificates 198 * from the demo keystore (created by running @link demo.keystore.SetupCMSKeySrore) 199 * stored at "cms.keystore" in your current working directoy. 200 */ 201 public SignedReceiptDemo() { 202 203 System.out.println(); 204 System.out.println("******************************************************************************************"); 205 System.out.println("* SignedReceiptDemo *"); 206 System.out.println("* (shows the usage of the IAIK-CMS library for handling ESS signed receipts) *"); 207 System.out.println("******************************************************************************************"); 208 System.out.println(); 209 210 // get the certificates from the KeyStore 211 signerCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 212 signerPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_1); 213 signerCertificate_ = signerCertificates_[0]; 214 encryptionCertOfSigner_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_1)[0]; 215 recipientCertificates_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_2); 216 recipientPrivateKey_ = CMSKeyStore.getPrivateKey(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_SIGN_2); 217 recipientCertificate_ = recipientCertificates_[0]; 218 encryptionCertOfRecipient_ = CMSKeyStore.getCertificateChain(CMSKeyStore.RSA, CMSKeyStore.SZ_2048_CRYPT_2)[0]; 219 signerCertificatesOfMLA_ = CMSKeyStore.getCertificateChain(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1); 220 signerPrivateKeyOfMLA_ = CMSKeyStore.getPrivateKey(CMSKeyStore.DSA, CMSKeyStore.SZ_2048_SIGN_1); 221 X509Certificate[] tmpCerts = new X509Certificate[signerCertificates_.length + 1]; 222 System.arraycopy(signerCertificates_, 0, tmpCerts, 0, signerCertificates_.length); 223 tmpCerts[signerCertificates_.length] = encryptionCertOfSigner_; 224 signerCertificates_ = tmpCerts; 225 tmpCerts = new X509Certificate[recipientCertificates_.length + 1]; 226 System.arraycopy(recipientCertificates_, 0, tmpCerts, 0, recipientCertificates_.length); 227 tmpCerts[recipientCertificates_.length] = encryptionCertOfRecipient_; 228 recipientCertificates_ = tmpCerts; 229 } 230 231 /** 232 * Starts the SignedReceipt demo. 233 */ 234 public void start() { 235 boolean implicit = true; 236 boolean mla = false; 237 System.out.println("Testing receipt request - signed receipt (all implicit)"); 238 test(implicit, mla); 239 mla = true; 240 System.out.println("Testing receipt request - MLA - signed receipt (all implicit)"); 241 test(implicit, mla); 242 implicit = false; 243 mla = false; 244 System.out.println("Testing receipt request - signed receipt (all explicit)"); 245 test(implicit, mla); 246 mla = true; 247 System.out.println("Testing receipt request - MLA - signed receipt (all explicit)"); 248 test(implicit, mla); 249 System.out.println("Ready!"); 250 } 251 252 /** 253 * Runs the ReceiptRequest - SignedReceipt test. 254 * 255 * @param implicit whether to create implicit (application/pkcs7-mime) or 256 * explicit (multipart/signed) ReceiptRequest messages 257 * 258 * @param mla whether to add a MLA layer 259 */ 260 public void test(boolean implicit, boolean mla) { 261 262 try { 263 // get the default Session 264 Session session = DemoSMimeUtil.getSession(); 265 266 Message msg; // the message to send 267 ByteArrayOutputStream baos = new ByteArrayOutputStream(); // we write to a stream 268 ByteArrayInputStream bais; // we read from a stream 269 270 // we send a signed message with a receipt request 271 System.out.println("Creating implicit signed message with receipt request."); 272 // create message and "send" it (write it to baos) 273 msg = createSignedMessageWithReceiptRequest(session, implicit, baos); 274 275 // now parse the receipt request message 276 bais = new ByteArrayInputStream(baos.toByteArray()); 277 msg = new MimeMessage(session, bais); 278 if (DUMP_MESSAGES) { 279 dumpMessage(msg); 280 } 281 baos.reset(); 282 283 if (mla == true) { 284 // MLA receives the message and adds a MLExpansionHistory that supersedes the 285 // original receipt request 286 System.out.println("MLA: parsing received original message."); 287 SignedContent sc = (SignedContent)msg.getContent(); 288 System.out.println("MLA: Verifying signature."); 289 // verify the signature (we assume only one signer) 290 X509Certificate signer = sc.verify(); 291 System.out.println("MLA: This message is signed from: "+signer.getSubjectDN()); 292 // add MLExpansionHistory 293 System.out.println("MLA: Creating new signed message with MLExpansionHistory attribute."); 294 SignedContent mlaSc = new SignedContent(sc, implicit); 295 mlaSc.setCertificates(signerCertificatesOfMLA_); 296 try { 297 SMimeSignerInfo signerInfo = new SMimeSignerInfo(signerCertificatesOfMLA_[0], 298 (AlgorithmID)AlgorithmID.sha256.clone(), 299 (AlgorithmID)AlgorithmID.dsaWithSHA256.clone(), 300 signerPrivateKeyOfMLA_); 301 // add a MLExpansionHistory attribute superseding the original receipt request 302 MLExpansionHistory mlExpansionHistory = createMLExpansionHistory(signerCertificatesOfMLA_[0], 303 new Date(), 304 mlaAddress_); 305 signerInfo.addSignedAttribute(new Attribute(mlExpansionHistory)); 306 mlaSc.addSigner(signerInfo); 307 } catch (NoSuchAlgorithmException ex) { 308 throw new MessagingException("Algorithm not supported: " + ex.getMessage(), ex); 309 } 310 msg = createMessage(session, mlaAddress_, recipientAddress_, "IAIK-S/MIME: MLA with ReceiptRequest"); 311 msg.setContent(mlaSc, mlaSc.getContentType()); 312 // let the SignedContent update some message headers 313 mlaSc.setHeaders(msg); 314 msg.saveChanges(); 315 msg.writeTo(baos); 316 317 // now parse the MLA message 318 bais = new ByteArrayInputStream(baos.toByteArray()); 319 msg = new MimeMessage(session, bais); 320 321 if (DUMP_MESSAGES) { 322 dumpMessage(msg); 323 } 324 } 325 326 // signed receipt creation 327 baos.reset(); 328 Message msg1 = createMessageWithSignedReceipt(session, msg); 329 msg1.saveChanges(); 330 msg1.writeTo(baos); 331 bais = new ByteArrayInputStream(baos.toByteArray()); 332 msg = new MimeMessage(session, bais); 333 334 if (DUMP_MESSAGES) { 335 dumpMessage(msg); 336 } 337 // signed receipt validation 338 System.out.println("\nNow getting and verifying signed receipt:"); 339 verifyReceiptContent(msg); 340 341 } catch (Exception ex) { 342 ex.printStackTrace(); 343 throw new RuntimeException(ex.toString()); 344 } 345 346 347 } 348 349 /** 350 * Creates a MimeMessage. 351 * 352 * @param session the current mail session 353 * @param from the sender of the message 354 * @param to the recipient of the message 355 * @param subject the subject of the message 356 * 357 * @return the newly created MimeMessage 358 * 359 * @throws MessagingException if an error occurs when creating the message 360 */ 361 public Message createMessage(Session session, String from, String to, String subject) throws MessagingException { 362 MimeMessage msg = new MimeMessage(session); 363 msg.setFrom(new InternetAddress(from)); 364 msg.setRecipients(Message.RecipientType.TO, InternetAddress.parse(to, false)); 365 msg.setSentDate(new Date()); 366 return msg; 367 } 368 369 /** 370 * Creates a signed message that contains a <code>ReceiptRequest</code> attribute. 371 * 372 * @param session the current mail session 373 * @param implicit whether to sign the content implicitly or explicitly 374 * @param os the output stream to which to write the message 375 * 376 * @return the message containing a ReceiptRequest attribute 377 */ 378 public Message createSignedMessageWithReceiptRequest(Session session, 379 boolean implicit, 380 OutputStream os) 381 throws Exception { 382 383 Message msg = createMessage(session, senderAddress_, recipientAddress_, "IAIK-S/MIME: ReceiptRequest"); 384 385 // create the inner signed content 386 SignedContent sc = new SignedContent(implicit, implicit ? SignedContent.SIGNED_DATA : null); 387 sc.setText("This is a signed message with a ReceiptRequest."); 388 389 sc.setCertificates(signerCertificates_); 390 SMimeSignerInfo signerInfo = new SMimeSignerInfo(signerCertificate_, 391 (AlgorithmID)AlgorithmID.sha256.clone(), 392 (AlgorithmID)AlgorithmID.rsaEncryption.clone(), 393 signerPrivateKey_, 394 encryptionCertOfSigner_, 395 true); 396 // add a ReceiptRequest attribute to request a receipt to be sent back to the sender 397 ReceiptRequest receiptRequest = createReceiptRequest(signerCertificate_.getPublicKey(), 398 msg.getSentDate(), 399 senderAddress_); 400 signerInfo.addSignedAttribute(new Attribute(receiptRequest)); 401 sc.addSigner(signerInfo); 402 msg.setContent(sc, sc.getContentType()); 403 // let the SignedContent update some message headers 404 sc.setHeaders(msg); 405 msg.saveChanges(); 406 msg.writeTo(os); 407 // now after sending (writing) the message we can access and keep the digest values for later SignedReceipt validation 408 storeDigestValues(sc); 409 return msg; 410 } 411 412 /** 413 * Creates a ReceiptRequest attribute to request all recipients to send 414 * a signed receipt to the entity to the given email address. 415 * 416 * @param publicKey the public key of the sender (used for ContentIdentifier calculation) 417 * @param sentDate the sent date of the message (used for ContentIdentifier calculation) 418 * @param email the email address of the sender (to whom to return a signed receipt) 419 * 420 * @return the ReceiptRequest 421 */ 422 public ReceiptRequest createReceiptRequest(PublicKey publicKey, Date sentDate, String email) { 423 // we request a receipt from all recipients 424 ReceiptsFrom receiptsFrom = new ReceiptsFrom(ReceiptsFrom.ALL_RECIPIENTS); 425 // the receipt should be send to the given email 426 String[] sendTo = { email }; 427 // create the signed content identifier 428 ContentIdentifier contentIdentifier = new ContentIdentifier(publicKey, sentDate, null); 429 // create the receipt request 430 ReceiptRequest receiptRequest = new ReceiptRequest(contentIdentifier, receiptsFrom, sendTo); 431 return receiptRequest; 432 } 433 434 /** 435 * Creates a MLExpansionHistory containing only one MLData for 436 * the given MLA with given expansion time and a MLReceiptPolicy 437 * of type IN_ADDITION_TO for the given mlaEmailAddress. 438 * 439 * @param mlaCertificate the certificate of the MLA from which to create the 440 * MLData EntityIdentiifier of type IssuerAndSerialNumber 441 * @param expansionTime the expansion time 442 * @param mlaEmailAddress to be set as IN_ADDITION_TO recipient list for 443 * the MLData MLRecipientPolicy 444 * 445 * @return the newly created MLExpansionHistory 446 */ 447 public static MLExpansionHistory createMLExpansionHistory(X509Certificate mlaCertificate, 448 Date expansionTime, 449 String mlaEmailAddress) { 450 451 IssuerAndSerialNumber ias = new IssuerAndSerialNumber(mlaCertificate); 452 MLData mlData = new MLData(new EntityIdentifier(ias), expansionTime); 453 MLReceiptPolicy mlReceiptPolicy = new MLReceiptPolicy(MLReceiptPolicy.IN_ADDITION_TO); 454 mlReceiptPolicy.setRecipientList(new String[] { mlaEmailAddress }); 455 mlData.setMLReceiptPolicy(mlReceiptPolicy); 456 return new MLExpansionHistory(mlData); 457 } 458 459 /** 460 * Keeps the signature message digest value of the sender and the receipt content digest 461 * values for later SignedReceipt validation. 462 * 463 * @param signedContent the signed message for which to keep the digest values 464 * 465 * @throws ESSException if an error occurs while gathering the required digest values 466 */ 467 public void storeDigestValues(SignedContent signedContent) throws ESSException { 468 SignerInfo originatorSignerInfo = signedContent.getSignerInfos()[0]; 469 SenderAndReceiptContentDigest.storeEntry(new SenderAndReceiptContentDigest(originatorSignerInfo)); 470 } 471 472 /** 473 * Creates a signed-receipt message from the received message. 474 * 475 * @param session the current mail session 476 * @param receivedMsg the message containing a ReceiptRequest attribute 477 * 478 * @return a message containing s signed receipt to be sent in return 479 * to the receipt request 480 * 481 * @throws Exception if some error occurs during receipt request processing 482 * or signed receipt creation 483 */ 484 public Message createMessageWithSignedReceipt(Session session, Message receivedMsg) 485 throws Exception { 486 487 SignedReceipt signedReceipt = new SignedReceipt(receivedMsg, recipientAddress_, System.out); 488 String subject = "IAIK-S/MIME: Signed Receipt"; 489 490 Message msg = signedReceipt.createReceiptMessage(recipientPrivateKey_, 491 recipientCertificates_, 492 recipientCertificates_[0], 493 (AlgorithmID)AlgorithmID.sha256.clone(), 494 (AlgorithmID)AlgorithmID.rsaEncryption.clone(), 495 encryptionCertOfRecipient_, 496 true, 497 session, 498 subject); 499 return msg; 500 } 501 502 503 /** 504 * Validates a signed receipt message received in return to a receipt request 505 * message. 506 * 507 * @param receiptMsg the message containing the signed receipt 508 * 509 * @throws Exception if the receipt validation fails for some reason 510 */ 511 public void verifyReceiptContent(Message receiptMsg) throws Exception { 512 // we assume to already know of the signed content 513 ReceiptContent receiptContent = (ReceiptContent)receiptMsg.getContent(); 514 515 Receipt receipt = (Receipt)receiptContent.getContent(); 516 System.out.println("\nReceipt received:"); 517 System.out.println(receipt); 518 519 520 // verify the signature (we assume only one signer) 521 X509Certificate receiptSigner = null; 522 try { 523 receiptSigner = receiptContent.verify(); 524 System.out.println("This receipt content is signed from: "+receiptSigner.getSubjectDN()); 525 } catch (SignatureException ex) { 526 System.err.println("Signature verification error!"); 527 throw ex; 528 } 529 530 531 try { 532 SenderAndReceiptContentDigest sarcd = SenderAndReceiptContentDigest.validateReceiptContent(receiptContent); 533 // now after validation we may remove the kept digest values from the repository 534 SenderAndReceiptContentDigest.removeEntry(sarcd); 535 } catch (ESSException ex) { 536 System.err.println("Signed Receipt validation error!"); 537 throw ex; 538 } 539 System.out.println("ReceiptContent successful validated!"); 540 } 541 542 /** 543 * Dumps the given message to System.out. 544 * 545 * @param msg the message to be dumped 546 * 547 * @throws Exception if some error occurs 548 */ 549 private static void dumpMessage(Message msg) throws Exception { 550 System.out.println("******************************************************************"); 551 System.out.println("Message dump: \n"); 552 msg.writeTo(System.out); 553 System.out.println("******************************************************************"); 554 } 555 556 /** 557 * Main method. 558 */ 559 public static void main(String[] argv) throws IOException { 560 561 try { 562 DemoSMimeUtil.initDemos(); 563 (new SignedReceiptDemo()).start(); 564 } catch (Exception ex) { 565 ex.printStackTrace(); 566 } 567 568 DemoUtil.waitKey(); 569 570 } 571 }