1 /************************************************************************
2 * Copyright (c) 2000-2006 The Apache Software Foundation. *
3 * All rights reserved. *
4 * ------------------------------------------------------------------- *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you *
6 * may not use this file except in compliance with the License. You *
7 * may obtain a copy of the License at: *
8 * *
9 * http://www.apache.org/licenses/LICENSE-2.0 *
10 * *
11 * Unless required by applicable law or agreed to in writing, software *
12 * distributed under the License is distributed on an "AS IS" BASIS, *
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or *
14 * implied. See the License for the specific language governing *
15 * permissions and limitations under the License. *
16 ***********************************************************************/
17
18 package org.apache.james.transport.mailets.smime;
19
20 import java.io.IOException;
21 import java.security.GeneralSecurityException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Iterator;
25
26 import javax.mail.MessagingException;
27 import javax.mail.Multipart;
28 import javax.mail.Part;
29 import javax.mail.internet.MimeBodyPart;
30 import javax.mail.internet.MimeMessage;
31
32 import org.apache.james.security.KeyHolder;
33 import org.apache.mailet.GenericMailet;
34 import org.apache.mailet.Mail;
35 import org.apache.mailet.MailetConfig;
36 import org.bouncycastle.cms.CMSException;
37 import org.bouncycastle.cms.RecipientId;
38 import org.bouncycastle.cms.RecipientInformation;
39 import org.bouncycastle.mail.smime.SMIMEEnveloped;
40 import org.bouncycastle.mail.smime.SMIMEUtil;
41
42 /***
43 * This mailet decrypts a s/mime encrypted message. It takes as input an
44 * encrypted message and it tries to dechiper it using the key specified in its
45 * configuration. If the decryption is successful the mail will be changed and
46 * it will contain the decrypted message. The mail attribute
47 * <code>org.apache.james.SMIMEDecrypt</code> will contain the public
48 * certificate of the key used in the process.
49 *
50 * The configuration parameters of this mailet are summarized below. The firsts
51 * define the keystore where the key that will be used to decrypt messages is
52 * saved.
53 * <ul>
54 * <li>keyStoreType (default: system dependent): defines the type of the store.
55 * Usually jks, pkcs12 or pkcs7</li>
56 * <li>keyStoreFileName (mandatory): private key store path.</li>
57 * <li>keyStorePassword (default: ""): private key store password</li>
58 * </ul>
59 * The other parameters define which private key have to be used. (if the store
60 * contains more than one key).
61 * <ul>
62 * <li>keyAlias: private key alias.</li>
63 * <li>keyPass: private key password</li>
64 * </ul>
65 *
66 */
67 public class SMIMEDecrypt extends GenericMailet {
68
69 private KeyHolder keyHolder;
70 protected String mailAttribute = "org.apache.james.SMIMEDecrypt";
71
72 public void init() throws MessagingException {
73 super.init();
74
75 MailetConfig config = getMailetConfig();
76
77 String privateStoreType = config.getInitParameter("keyStoreType");
78
79 String privateStoreFile = config.getInitParameter("keyStoreFileName");
80 if (privateStoreFile == null) throw new MessagingException("No keyStoreFileName specified");
81
82 String privateStorePass = config.getInitParameter("keyStorePassword");
83
84 String keyAlias= config.getInitParameter("keyAlias");
85 String keyPass = config.getInitParameter("keyAliasPassword");
86
87 String mailAttributeConf = config.getInitParameter("mailAttribute");
88 if (mailAttributeConf != null) mailAttribute = mailAttributeConf;
89
90 try {
91 keyHolder = new KeyHolder(privateStoreFile, privateStorePass, keyAlias, keyPass, privateStoreType);
92 } catch (IOException e) {
93 throw new MessagingException("Error loading keystore", e);
94 } catch (GeneralSecurityException e) {
95 throw new MessagingException("Error loading keystore", e);
96 }
97
98
99 }
100
101
102
103 public void service(Mail mail) throws MessagingException {
104 MimeMessage message = mail.getMessage();
105 Part strippedMessage = null;
106 log("Starting message decryption..");
107 if (message.isMimeType("application/x-pkcs7-mime") || message.isMimeType("application/pkcs7-mime")) {
108 try {
109 SMIMEEnveloped env = new SMIMEEnveloped(message);
110 Collection recipients = env.getRecipientInfos().getRecipients();
111 for (Iterator iter = recipients.iterator();iter.hasNext();) {
112 RecipientInformation info = (RecipientInformation) iter.next();
113 RecipientId id = info.getRID();
114 if (id.match(keyHolder.getCertificate())) {
115 try {
116 MimeBodyPart part = SMIMEUtil.toMimeBodyPart(info.getContent(keyHolder.getPrivateKey(), "BC"));
117
118 strippedMessage = part;
119 log("Encrypted message decrypted");
120 } catch (Exception e) {
121 throw new MessagingException("Error during the decryption of the message", e); }
122 } else {
123 log("Found an encrypted message but it isn't encrypted for the supplied key");
124 }
125 }
126 } catch (CMSException e) { throw new MessagingException("Error during the decryption of the message",e); }
127 }
128
129
130 if (strippedMessage != null) {
131
132
133
134
135
136 ArrayList list = new ArrayList(1);
137 list.add(keyHolder.getCertificate());
138 mail.setAttribute(mailAttribute, list);
139
140
141 try {
142 MimeMessage newmex = new MimeMessage(message);
143 Object obj = strippedMessage.getContent();
144 if (obj instanceof Multipart) {
145 log("The message is multipart, content type "+((Multipart)obj).getContentType());
146 newmex.setContent((Multipart)obj);
147 } else {
148 newmex.setContent(obj, strippedMessage.getContentType());
149 newmex.setDisposition(null);
150 }
151 newmex.saveChanges();
152 mail.setMessage(newmex);
153 } catch (IOException e) {
154 log("Error during the strip of the encrypted message");
155 throw new MessagingException("Error during the stripping of the encrypted message",e);
156 }
157 }
158 }
159 }