All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.james.jdkim.mailets.DKIMSign Maven / Gradle / Ivy

The newest version!
/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you under the Apache License, Version 2.0 (the            *
 * "License"); you may not use this file except in compliance   *
 * with the License.  You may obtain a copy of the License at   *
 *                                                              *
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
 *                                                              *
 * Unless required by applicable law or agreed to in writing,   *
 * software distributed under the License is distributed on an  *
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
 * KIND, either express or implied.  See the License for the    *
 * specific language governing permissions and limitations      *
 * under the License.                                           *
 ****************************************************************/

package org.apache.james.jdkim.mailets;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.mail.Header;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;

import org.apache.commons.ssl.PKCS8Key;
import org.apache.james.jdkim.DKIMSigner;
import org.apache.james.jdkim.api.BodyHasher;
import org.apache.james.jdkim.api.Headers;
import org.apache.james.jdkim.api.SignatureRecord;
import org.apache.james.jdkim.exceptions.PermFailException;
import org.apache.mailet.Mail;
import org.apache.mailet.base.GenericMailet;

/**
 * This mailet sign a message using the DKIM protocol
 * If the privateKey is encoded using a password then you can pass
 * the password as privateKeyPassword parameter.
 * 
 * Sample configuration:
 * 
 * 

 * <mailet match="All" class="DKIMSign">
 *   <signatureTemplate>v=1; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;</signatureTemplate>
 *   <privateKey>
 *   -----BEGIN RSA PRIVATE KEY-----
 *   MIICXAIBAAKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoT
 *   M5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRH
 *   r7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB
 *   AoGBAI8XcwnZi0Sq5N89wF+gFNhnREFo3rsJDaCY8iqHdA5DDlnr3abb/yhipw0I
 *   /1HlgC6fIG2oexXOXFWl+USgqRt1kTt9jXhVFExg8mNko2UelAwFtsl8CRjVcYQO
 *   cedeH/WM/mXjg2wUqqZenBmlKlD6vNb70jFJeVaDJ/7n7j8BAkEA9NkH2D4Zgj/I
 *   OAVYccZYH74+VgO0e7VkUjQk9wtJ2j6cGqJ6Pfj0roVIMUWzoBb8YfErR8l6JnVQ
 *   bfy83gJeiQJBAOHk3ow7JjAn8XuOyZx24KcTaYWKUkAQfRWYDFFOYQF4KV9xLSEt
 *   ycY0kjsdxGKDudWcsATllFzXDCQF6DTNIWECQEA52ePwTjKrVnLTfCLEG4OgHKvl
 *   Zud4amthwDyJWoMEH2ChNB2je1N4JLrABOE+hk+OuoKnKAKEjWd8f3Jg/rkCQHj8
 *   mQmogHqYWikgP/FSZl518jV48Tao3iXbqvU9Mo2T6yzYNCCqIoDLFWseNVnCTZ0Q
 *   b+IfiEf1UeZVV5o4J+ECQDatNnS3V9qYUKjj/krNRD/U0+7eh8S2ylLqD3RlSn9K
 *   tYGRMgAtUXtiOEizBH6bd/orzI9V9sw8yBz+ZqIH25Q=
 *   -----END RSA PRIVATE KEY-----
 *   </privateKey>
 * </mailet>
 * 
* * By default the mailet assume that Javamail will convert LF to CRLF when sending * so will compute the hash using converted newlines. If you don't want this * behaviout then set forceCRLF attribute to false. */ public class DKIMSign extends GenericMailet { private String signatureTemplate; private PrivateKey privateKey; private boolean forceCRLF; /** * @return the signatureTemplate */ protected String getSignatureTemplate() { return signatureTemplate; } /** * @return the privateKey */ protected PrivateKey getPrivateKey() { return privateKey; } public void init() throws MessagingException { signatureTemplate = getInitParameter("signatureTemplate"); String privateKeyString = getInitParameter("privateKey"); String privateKeyPassword = getInitParameter("privateKeyPassword", null); forceCRLF = getInitParameter("forceCRLF", true); try { PKCS8Key pkcs8 = new PKCS8Key(new ByteArrayInputStream( privateKeyString.getBytes()), privateKeyPassword != null ? privateKeyPassword .toCharArray() : null); privateKey = pkcs8.getPrivateKey(); // privateKey = DKIMSigner.getPrivateKey(privateKeyString); } catch (NoSuchAlgorithmException e) { throw new MessagingException("Unknown private key algorythm: " + e.getMessage(), e); } catch (InvalidKeySpecException e) { throw new MessagingException( "PrivateKey should be in base64 encoded PKCS8 (der) format: " + e.getMessage(), e); } catch (GeneralSecurityException e) { throw new MessagingException("General security exception: " + e.getMessage(), e); } } public void service(Mail mail) throws MessagingException { DKIMSigner signer = new DKIMSigner(getSignatureTemplate(), getPrivateKey()); SignatureRecord signRecord = signer .newSignatureRecordTemplate(getSignatureTemplate()); try { BodyHasher bhj = signer.newBodyHasher(signRecord); MimeMessage message = mail.getMessage(); Headers headers = new MimeMessageHeaders(message); try { OutputStream os = new HeaderSkippingOutputStream(bhj.getOutputStream()); if (forceCRLF) os = new CRLFOutputStream(os); message.writeTo(os); bhj.getOutputStream().close(); } catch (IOException e) { throw new MessagingException("Exception calculating bodyhash: " + e.getMessage(), e); } String signatureHeader = signer.sign(headers, bhj); // Unfortunately JavaMail does not give us a method to add headers // on top. // message.addHeaderLine(signatureHeader); prependHeader(message, signatureHeader); } catch (PermFailException e) { throw new MessagingException("PermFail while signing: " + e.getMessage(), e); } } @SuppressWarnings("unchecked") private void prependHeader(MimeMessage message, String signatureHeader) throws MessagingException { List prevHeader = new LinkedList(); // read all the headers for (Enumeration e = message.getAllHeaderLines(); e.hasMoreElements();) { String headerLine = e.nextElement(); prevHeader.add(headerLine); } // remove all the headers for (Enumeration
e = message.getAllHeaders(); e.hasMoreElements();) { Header header = e.nextElement(); message.removeHeader(header.getName()); } // add our header message.addHeaderLine(signatureHeader); // add the remaining headers using "addHeaderLine" that won't alter the // insertion order. for (Iterator i = prevHeader.iterator(); i.hasNext();) { String header = i.next(); message.addHeaderLine(header); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy