Java tutorial
/* * Copyright (c) 2008-2012, Martijn Brinkers, Djigzo. * * This file is part of Djigzo email encryption. * * Djigzo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License * version 3, 19 November 2007 as published by the Free Software * Foundation. * * Djigzo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public * License along with Djigzo. If not, see <http://www.gnu.org/licenses/> * * Additional permission under GNU AGPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, * wsdl4j-1.6.1.jar (or modified versions of these libraries), * containing parts covered by the terms of Eclipse Public License, * tyrex license, freemarker license, dom4j license, mx4j license, * Spice Software License, Common Development and Distribution License * (CDDL), Common Public License (CPL) the licensors of this Program grant * you additional permission to convey the resulting work. */ package mitm.application.djigzo.james.mailets; import java.io.IOException; import java.security.cert.X509Certificate; import java.util.Collection; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import mitm.application.djigzo.james.Certificates; import mitm.application.djigzo.james.DjigzoMailAttributes; import mitm.application.djigzo.james.DjigzoMailAttributesImpl; import mitm.common.mail.MimeMessageWithID; import mitm.common.security.smime.SMIMEBuilder; import mitm.common.security.smime.SMIMEBuilderException; import mitm.common.security.smime.SMIMEBuilderImpl; import mitm.common.security.smime.SMIMEEncryptionAlgorithm; import mitm.common.security.smime.SMIMERecipientMode; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.text.StrBuilder; import org.apache.mailet.Mail; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * S/MIME encrypts the message using the certificates from the mail attributes (See {@link DjigzoMailAttributes#getCertificates()}) * If there are no certificates the mail will not be encrypted. * * The following mailet parameters are supported: * * algorithm : The secret key encryption algorithm to use (default: 3DES) * algorithmAttribute : The Mail attribute to read the secret key encryption algorithm from * keySize : The size of the secret key (default: default (max) key size for the algorithm) * recipientMode : What method to use for certificate id. One of ISSUER_SERIAL, SUBJECT_KEY_ID_IF_AVAILABLE or BOTH * (default: ISSUER_SERIAL) * protectedHeader : Header that should be add to the encrypted blob (can be more than one protectedHeader) * retainMessageID : If true the original Message-ID will be used for the encrypted message * catchRuntimeExceptions : If true all RunTimeExceptions are caught (default: true) * catchErrors : If true all Errors are caught (default: true) * * @author Martijn Brinkers * */ public class SMIMEEncrypt extends AbstractDjigzoMailet { private final static Logger logger = LoggerFactory.getLogger(SMIMEEncrypt.class); /* * The mailet initialization parameters used by this mailet. */ private enum Parameter { ALGORITHM("algorithm"), ALGORITHM_ATTRIBUTE("algorithmAttribute"), KEY_SIZE("keySize"), RECIPIENT_MODE( "recipientMode"), USE_DEPRECATED_CONTENT_TYPES("useDeprecatedContentTypes"), PROTECTED_HEADER( "protectedHeader"), RETAIN_MESSAGE_ID("retainMessageID"); private String name; private Parameter(String name) { this.name = name; } }; /* * How should the certificate be identified in the encrypted blob */ private SMIMERecipientMode recipientMode = SMIMERecipientMode.ISSUER_SERIAL; /* * The encryption algorithm */ private SMIMEEncryptionAlgorithm encryptionAlgorithm = SMIMEEncryptionAlgorithm.DES_EDE3_CBC; /* * The Mail attribute from which the encryption algorithm is read. If null or if there is no * attribute with the given name, the encryptionAlgorithm is used. */ private String encryptionAlgorithmAttribute; /* * Key size to use. Only applicable when the algorithm supports varaiable key size */ private Integer keySize; /* * If true the old x-pkcs7-* content types will be used */ private boolean useDeprecatedContentTypes; /* * If true the original Message-ID will be used for the encrypted message */ private boolean retainMessageID = true; /* * Determines which headers will be encrypted. */ private String[] protectedHeaders = new String[] {}; @Override protected Logger getLogger() { return logger; } protected SMIMERecipientMode getRecipientMode() { return recipientMode; } protected SMIMEEncryptionAlgorithm getEncryptionAlgorithm(Mail mail) { SMIMEEncryptionAlgorithm encryptionAlgorithm = null; /* * Check if the Mail attribute contains the encryption algorithm */ if (StringUtils.isNotEmpty(encryptionAlgorithmAttribute)) { Object attributeValue = mail.getAttribute(encryptionAlgorithmAttribute); if (attributeValue != null) { if (attributeValue instanceof String) { encryptionAlgorithm = SMIMEEncryptionAlgorithm.fromName((String) attributeValue); if (encryptionAlgorithm == null) { getLogger().warn("The attribute value {} is not a valid algorithm.", attributeValue); } } else { getLogger().warn("Attribute {} is not a String but a ", encryptionAlgorithmAttribute, attributeValue.getClass()); } } else { getLogger().debug("Attribute with name {} was not found", encryptionAlgorithmAttribute); } } if (encryptionAlgorithm == null) { /* * Use the default encryption algorithm */ encryptionAlgorithm = this.encryptionAlgorithm; } getLogger().debug("Encryption algorithm: {}", encryptionAlgorithm); return encryptionAlgorithm; } private void initProtectedHeaders() { String param = getInitParameter(Parameter.PROTECTED_HEADER.name); if (param != null) { protectedHeaders = param.split("\\s*,\\s*"); } } @Override final public void initMailet() { getLogger().info("Initializing mailet: " + getMailetName()); String param = getInitParameter(Parameter.ALGORITHM.name); if (param != null) { encryptionAlgorithm = SMIMEEncryptionAlgorithm.fromName(param); if (encryptionAlgorithm == null) { throw new IllegalArgumentException(param + " is not a valid encryption algorithm."); } } encryptionAlgorithmAttribute = getInitParameter(Parameter.ALGORITHM_ATTRIBUTE.name); param = getInitParameter(Parameter.KEY_SIZE.name); if (param != null) { keySize = Integer.valueOf(param); if (keySize <= 0) { throw new IllegalArgumentException("KeySize must be > 0"); } } param = getInitParameter(Parameter.RECIPIENT_MODE.name); if (param != null) { recipientMode = SMIMERecipientMode.fromName(param); if (recipientMode == null) { throw new IllegalArgumentException(recipientMode + " is not a valid SMIMERecipientMode."); } } param = getInitParameter(Parameter.USE_DEPRECATED_CONTENT_TYPES.name); if (param != null) { useDeprecatedContentTypes = BooleanUtils.toBoolean(param); } param = getInitParameter(Parameter.RETAIN_MESSAGE_ID.name); if (param != null) { retainMessageID = BooleanUtils.toBoolean(param); } initProtectedHeaders(); StrBuilder sb = new StrBuilder(); sb.append("Algorithm: "); sb.append(encryptionAlgorithm); sb.appendSeparator("; "); sb.append("Algorithm attribute: "); sb.append(encryptionAlgorithmAttribute); sb.appendSeparator("; "); sb.append("KeySize: "); sb.append(keySize); sb.appendSeparator("; "); sb.append("Recipient Mode: "); sb.append(recipientMode); sb.appendSeparator("; "); sb.append("Use deprecated content-type's: "); sb.append(useDeprecatedContentTypes); sb.appendSeparator("; "); sb.append("Retain Message-ID: "); sb.append(retainMessageID); sb.appendSeparator("; "); sb.append("Protected headers: "); sb.append(StringUtils.join(protectedHeaders, ",")); getLogger().info(sb.toString()); } private String[] getProtectedHeaders(Mail mail) { /* * Get the protected headers from mail if available, if not available use the protected headers */ DjigzoMailAttributes attributes = new DjigzoMailAttributesImpl(mail); String[] protectedHeaders = attributes.getProtectedHeaders(); if (protectedHeaders == null) { protectedHeaders = this.protectedHeaders; } if (getLogger().isDebugEnabled()) { getLogger().debug("Protected headers: {}", StringUtils.join(protectedHeaders, ", ")); } return protectedHeaders; } @Override public void serviceMail(Mail mail) { try { DjigzoMailAttributes mailAttributes = new DjigzoMailAttributesImpl(mail); Certificates certificateStore = mailAttributes.getCertificates(); if (certificateStore != null) { Collection<X509Certificate> certificates = certificateStore.getCertificates(); if (certificates.size() > 0) { MimeMessage message = mail.getMessage(); if (message != null) { SMIMEBuilder sMIMEBuilder = new SMIMEBuilderImpl(message, getProtectedHeaders(mail)); sMIMEBuilder.setUseDeprecatedContentTypes(useDeprecatedContentTypes); for (X509Certificate certificate : certificates) { sMIMEBuilder.addRecipient(certificate, getRecipientMode()); } SMIMEEncryptionAlgorithm localAlgorithm = getEncryptionAlgorithm(mail); int localKeySize = (keySize != null ? keySize : localAlgorithm.defaultKeySize()); getLogger().debug("Encrypting the message. Encryption algorithm: {}, key size: {}", localAlgorithm, localKeySize); sMIMEBuilder.encrypt(localAlgorithm, localKeySize); MimeMessage encrypted = sMIMEBuilder.buildMessage(); if (encrypted != null) { encrypted.saveChanges(); /* * A new MimeMessage instance will be created. This makes ure that the * MimeMessage can be written by James (using writeTo()). The message-ID * of the source message will be retained if told to do so */ encrypted = retainMessageID ? new MimeMessageWithID(encrypted, message.getMessageID()) : new MimeMessage(encrypted); mail.setMessage(encrypted); } } else { getLogger().warn("Message is null."); } } else { getLogger().warn("Certificate collection is empty."); } } else { getLogger().warn("Certificates attribute not found."); } } catch (SMIMEBuilderException e) { getLogger().error("Error encrypting the message.", e); } catch (MessagingException e) { getLogger().error("Error reading the message.", e); } catch (IOException e) { getLogger().error("IOException.", e); } } public boolean isUseDeprecatedContentTypes() { return useDeprecatedContentTypes; } public boolean isRetainMessageID() { return retainMessageID; } public String[] getProtectedHeaders() { return protectedHeaders; } public void setRecipientMode(SMIMERecipientMode recipientMode) { this.recipientMode = recipientMode; } }