001: /****************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one *
003: * or more contributor license agreements. See the NOTICE file *
004: * distributed with this work for additional information *
005: * regarding copyright ownership. The ASF licenses this file *
006: * to you under the Apache License, Version 2.0 (the *
007: * "License"); you may not use this file except in compliance *
008: * with the License. You may obtain a copy of the License at *
009: * *
010: * http://www.apache.org/licenses/LICENSE-2.0 *
011: * *
012: * Unless required by applicable law or agreed to in writing, *
013: * software distributed under the License is distributed on an *
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
015: * KIND, either express or implied. See the License for the *
016: * specific language governing permissions and limitations *
017: * under the License. *
018: ****************************************************************/package org.apache.james.transport.mailets.smime;
019:
020: import java.io.IOException;
021: import java.security.GeneralSecurityException;
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.Iterator;
025:
026: import javax.mail.MessagingException;
027: import javax.mail.Multipart;
028: import javax.mail.Part;
029: import javax.mail.internet.MimeBodyPart;
030: import javax.mail.internet.MimeMessage;
031:
032: import org.apache.james.security.KeyHolder;
033: import org.apache.mailet.GenericMailet;
034: import org.apache.mailet.Mail;
035: import org.apache.mailet.MailetConfig;
036: import org.bouncycastle.cms.CMSException;
037: import org.bouncycastle.cms.RecipientId;
038: import org.bouncycastle.cms.RecipientInformation;
039: import org.bouncycastle.mail.smime.SMIMEEnveloped;
040: import org.bouncycastle.mail.smime.SMIMEUtil;
041:
042: /**
043: * This mailet decrypts a s/mime encrypted message. It takes as input an
044: * encrypted message and it tries to dechiper it using the key specified in its
045: * configuration. If the decryption is successful the mail will be changed and
046: * it will contain the decrypted message. The mail attribute
047: * <code>org.apache.james.SMIMEDecrypt</code> will contain the public
048: * certificate of the key used in the process.
049: *
050: * The configuration parameters of this mailet are summarized below. The firsts
051: * define the keystore where the key that will be used to decrypt messages is
052: * saved.
053: * <ul>
054: * <li>keyStoreType (default: system dependent): defines the type of the store.
055: * Usually jks, pkcs12 or pkcs7</li>
056: * <li>keyStoreFileName (mandatory): private key store path.</li>
057: * <li>keyStorePassword (default: ""): private key store password</li>
058: * </ul>
059: * The other parameters define which private key have to be used. (if the store
060: * contains more than one key).
061: * <ul>
062: * <li>keyAlias: private key alias.</li>
063: * <li>keyPass: private key password</li>
064: * </ul>
065: *
066: */
067: public class SMIMEDecrypt extends GenericMailet {
068:
069: private KeyHolder keyHolder;
070: protected String mailAttribute = "org.apache.james.SMIMEDecrypt";
071:
072: public void init() throws MessagingException {
073: super .init();
074:
075: MailetConfig config = getMailetConfig();
076:
077: String privateStoreType = config
078: .getInitParameter("keyStoreType");
079:
080: String privateStoreFile = config
081: .getInitParameter("keyStoreFileName");
082: if (privateStoreFile == null)
083: throw new MessagingException(
084: "No keyStoreFileName specified");
085:
086: String privateStorePass = config
087: .getInitParameter("keyStorePassword");
088:
089: String keyAlias = config.getInitParameter("keyAlias");
090: String keyPass = config.getInitParameter("keyAliasPassword");
091:
092: String mailAttributeConf = config
093: .getInitParameter("mailAttribute");
094: if (mailAttributeConf != null)
095: mailAttribute = mailAttributeConf;
096:
097: try {
098: keyHolder = new KeyHolder(privateStoreFile,
099: privateStorePass, keyAlias, keyPass,
100: privateStoreType);
101: } catch (IOException e) {
102: throw new MessagingException("Error loading keystore", e);
103: } catch (GeneralSecurityException e) {
104: throw new MessagingException("Error loading keystore", e);
105: }
106:
107: }
108:
109: /* (non-Javadoc)
110: * @see org.apache.mailet.Mailet#service(org.apache.mailet.Mail)
111: */
112: public void service(Mail mail) throws MessagingException {
113: MimeMessage message = mail.getMessage();
114: Part strippedMessage = null;
115: log("Starting message decryption..");
116: if (message.isMimeType("application/x-pkcs7-mime")
117: || message.isMimeType("application/pkcs7-mime")) {
118: try {
119: SMIMEEnveloped env = new SMIMEEnveloped(message);
120: Collection recipients = env.getRecipientInfos()
121: .getRecipients();
122: for (Iterator iter = recipients.iterator(); iter
123: .hasNext();) {
124: RecipientInformation info = (RecipientInformation) iter
125: .next();
126: RecipientId id = info.getRID();
127: if (id.match(keyHolder.getCertificate())) {
128: try {
129: MimeBodyPart part = SMIMEUtil
130: .toMimeBodyPart(info.getContent(
131: keyHolder.getPrivateKey(),
132: "BC"));
133: // strippedMessage contains the decrypted message.
134: strippedMessage = part;
135: log("Encrypted message decrypted");
136: } catch (Exception e) {
137: throw new MessagingException(
138: "Error during the decryption of the message",
139: e);
140: }
141: } else {
142: log("Found an encrypted message but it isn't encrypted for the supplied key");
143: }
144: }
145: } catch (CMSException e) {
146: throw new MessagingException(
147: "Error during the decryption of the message", e);
148: }
149: }
150:
151: // if the decryption has been successful..
152: if (strippedMessage != null) {
153: // I put the private key's public certificate as a mailattribute.
154: // I create a list of certificate because I want to minic the
155: // behavior of the SMIMEVerifySignature mailet. In that way
156: // it is possible to reuse the same matchers to analyze
157: // the result of the operation.
158: ArrayList list = new ArrayList(1);
159: list.add(keyHolder.getCertificate());
160: mail.setAttribute(mailAttribute, list);
161:
162: // I start the message stripping.
163: try {
164: MimeMessage newmex = new MimeMessage(message);
165: Object obj = strippedMessage.getContent();
166: if (obj instanceof Multipart) {
167: log("The message is multipart, content type "
168: + ((Multipart) obj).getContentType());
169: newmex.setContent((Multipart) obj);
170: } else {
171: newmex.setContent(obj, strippedMessage
172: .getContentType());
173: newmex.setDisposition(null);
174: }
175: newmex.saveChanges();
176: mail.setMessage(newmex);
177: } catch (IOException e) {
178: log("Error during the strip of the encrypted message");
179: throw new MessagingException(
180: "Error during the stripping of the encrypted message",
181: e);
182: }
183: }
184: }
185: }
|