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 }