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