blob: 2e46dd033c5959e49130cff7afeb05dd970f96dd [file] [log] [blame]
/****************************************************************
* 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 org.apache.james.jdkim.DKIMVerifier;
import org.apache.james.jdkim.MockPublicKeyRecordRetriever;
import org.apache.james.jdkim.api.SignatureRecord;
import org.apache.james.jdkim.exceptions.FailException;
import org.apache.james.jdkim.exceptions.PermFailException;
import org.apache.mailet.Mail;
import org.apache.mailet.Mailet;
import org.apache.mailet.base.test.FakeMail;
import org.apache.mailet.base.test.FakeMailContext;
import org.apache.mailet.base.test.FakeMailetConfig;
import org.junit.Assert;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import javax.mail.Address;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
public class DKIMSignTest {
private static final String TESTING_PEM = "-----BEGIN RSA PRIVATE KEY-----\r\n" +
"MIICXAIBAAKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoT\r\n" +
"M5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRH\r\n" +
"r7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB\r\n" +
"AoGBAI8XcwnZi0Sq5N89wF+gFNhnREFo3rsJDaCY8iqHdA5DDlnr3abb/yhipw0I\r\n" +
"/1HlgC6fIG2oexXOXFWl+USgqRt1kTt9jXhVFExg8mNko2UelAwFtsl8CRjVcYQO\r\n" +
"cedeH/WM/mXjg2wUqqZenBmlKlD6vNb70jFJeVaDJ/7n7j8BAkEA9NkH2D4Zgj/I\r\n" +
"OAVYccZYH74+VgO0e7VkUjQk9wtJ2j6cGqJ6Pfj0roVIMUWzoBb8YfErR8l6JnVQ\r\n" +
"bfy83gJeiQJBAOHk3ow7JjAn8XuOyZx24KcTaYWKUkAQfRWYDFFOYQF4KV9xLSEt\r\n" +
"ycY0kjsdxGKDudWcsATllFzXDCQF6DTNIWECQEA52ePwTjKrVnLTfCLEG4OgHKvl\r\n" +
"Zud4amthwDyJWoMEH2ChNB2je1N4JLrABOE+hk+OuoKnKAKEjWd8f3Jg/rkCQHj8\r\n" +
"mQmogHqYWikgP/FSZl518jV48Tao3iXbqvU9Mo2T6yzYNCCqIoDLFWseNVnCTZ0Q\r\n" +
"b+IfiEf1UeZVV5o4J+ECQDatNnS3V9qYUKjj/krNRD/U0+7eh8S2ylLqD3RlSn9K\r\n" +
"tYGRMgAtUXtiOEizBH6bd/orzI9V9sw8yBz+ZqIH25Q=\r\n" +
"-----END RSA PRIVATE KEY-----\r\n";
private static final FakeMailContext FAKE_MAIL_CONTEXT = FakeMailContext.defaultContext();
@Test
public void testDKIMSign() throws MessagingException, IOException,
FailException {
String message = "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bounce@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova\r\n";
Mailet mailet = new DKIMSign();
FakeMailetConfig mci = FakeMailetConfig.builder()
.mailetName("Test")
.mailetContext(FAKE_MAIL_CONTEXT)
.setProperty(
"signatureTemplate",
"v=1; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;")
.setProperty("privateKey", TESTING_PEM)
.build();
mailet.init(mci);
Mail mail = FakeMail.builder()
.mimeMessage(new MimeMessage(Session
.getDefaultInstance(new Properties()),
new ByteArrayInputStream(message.getBytes())))
.build();
mailet.service(mail);
Mailet m7bit = new ConvertTo7Bit();
m7bit.init(mci);
m7bit.service(mail);
ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
mail.getMessage().writeTo(rawMessage);
MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
"selector", "example.com");
verify(rawMessage, mockPublicKeyRecordRetriever);
}
private List<SignatureRecord> verify(ByteArrayOutputStream rawMessage,
MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever)
throws MessagingException, FailException {
List<SignatureRecord> signs = DKIMVerify.verify(new DKIMVerifier(mockPublicKeyRecordRetriever), new MimeMessage(Session.getDefaultInstance(new Properties()), new ByteArrayInputStream(rawMessage.toByteArray())), true);
assertNotNull(signs);
assertEquals(1, signs.size());
return signs;
}
@Test
public void testDKIMSignFuture() throws MessagingException, IOException,
FailException {
String message = "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bounce@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova\r\n";
Mailet mailet = new DKIMSign();
FakeMailetConfig mci = FakeMailetConfig.builder()
.mailetName("Test")
.mailetContext(FAKE_MAIL_CONTEXT)
.setProperty(
"signatureTemplate",
"v=1; t=" + ((System.currentTimeMillis() / 1000) + 1000) + "; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;")
.setProperty("privateKey", TESTING_PEM)
.build();
mailet.init(mci);
Mail mail = FakeMail.builder()
.mimeMessage(new MimeMessage(Session
.getDefaultInstance(new Properties()),
new ByteArrayInputStream(message.getBytes())))
.build();
mailet.service(mail);
Mailet m7bit = new ConvertTo7Bit();
m7bit.init(mci);
m7bit.service(mail);
ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
mail.getMessage().writeTo(rawMessage);
MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
"selector", "example.com");
try {
verify(rawMessage, mockPublicKeyRecordRetriever);
Assert.fail("Expecting signature to be ignored");
} catch (PermFailException e) {
// signature ignored, so fail for missing signatures.
}
}
@Test
public void testDKIMSignTime() throws MessagingException, IOException,
FailException {
String message = "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bounce@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova\r\n";
Mailet mailet = new DKIMSign();
FakeMailetConfig mci = FakeMailetConfig.builder()
.mailetName("Test")
.mailetContext(FAKE_MAIL_CONTEXT)
.setProperty(
"signatureTemplate",
"v=1; t=; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;")
.setProperty("privateKey", TESTING_PEM)
.build();
mailet.init(mci);
Mail mail = FakeMail.builder()
.mimeMessage(new MimeMessage(Session
.getDefaultInstance(new Properties()),
new ByteArrayInputStream(message.getBytes())))
.build();
mailet.service(mail);
Mailet m7bit = new ConvertTo7Bit();
m7bit.init(mci);
m7bit.service(mail);
ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
mail.getMessage().writeTo(rawMessage);
MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
"selector", "example.com");
verify(rawMessage, mockPublicKeyRecordRetriever);
List<SignatureRecord> rs = verify(rawMessage, mockPublicKeyRecordRetriever);
// check we have a valued signatureTimestamp
Assert.assertNotNull(rs.get(0).getSignatureTimestamp());
long ref = System.currentTimeMillis() / 1000;
// Chech that the signature timestamp is in the past 60 seconds.
Assert.assertTrue(rs.get(0).getSignatureTimestamp() <= ref);
Assert.assertTrue(rs.get(0).getSignatureTimestamp() >= ref - 60);
}
@Test
public void testDKIMSignMessageAsText() throws MessagingException,
IOException, FailException {
MimeMessage mm = new MimeMessage(Session
.getDefaultInstance(new Properties()));
mm.addFrom(new Address[]{new InternetAddress("io@bago.org")});
mm.addRecipient(RecipientType.TO, new InternetAddress("io@bago.org"));
mm.setText("An 8bit encoded body with \u20ACuro symbol.", "ISO-8859-15");
Mailet mailet = new DKIMSign();
FakeMailetConfig mci = FakeMailetConfig.builder()
.mailetName("Test")
.mailetContext(FAKE_MAIL_CONTEXT)
.setProperty(
"signatureTemplate",
"v=1; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;")
.setProperty("privateKey", TESTING_PEM)
.build();
mailet.init(mci);
Mail mail = FakeMail.builder()
.mimeMessage(mm)
.build();
Mailet m7bit = new ConvertTo7Bit();
m7bit.init(mci);
mailet.service(mail);
m7bit.service(mail);
ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
mail.getMessage().writeTo(rawMessage);
MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
"selector", "example.com");
verify(rawMessage, mockPublicKeyRecordRetriever);
}
@Test
public void testDKIMSignMessageAsObjectConvertedTo7Bit()
throws MessagingException, IOException, FailException {
MimeMessage mm = new MimeMessage(Session
.getDefaultInstance(new Properties()));
mm.addFrom(new Address[]{new InternetAddress("io@bago.org")});
mm.addRecipient(RecipientType.TO, new InternetAddress("io@bago.org"));
mm.setContent("An 8bit encoded body with \u20ACuro symbol.",
"text/plain; charset=iso-8859-15");
mm.setHeader("Content-Transfer-Encoding", "8bit");
mm.saveChanges();
FakeMailContext FakeMailContext = FAKE_MAIL_CONTEXT;
FakeMailContext.getServerInfo();
FakeMailetConfig mci = FakeMailetConfig.builder()
.mailetName("Test")
.mailetContext(FAKE_MAIL_CONTEXT)
.setProperty(
"signatureTemplate",
"v=1; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;")
.setProperty("privateKey", TESTING_PEM)
.build();
Mail mail = FakeMail.builder()
.mimeMessage(mm)
.build();
Mailet mailet = new DKIMSign();
mailet.init(mci);
Mailet m7bit = new ConvertTo7Bit();
m7bit.init(mci);
m7bit.service(mail);
mailet.service(mail);
m7bit.service(mail);
ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
mail.getMessage().writeTo(rawMessage);
MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
"selector", "example.com");
verify(rawMessage, mockPublicKeyRecordRetriever);
}
@Test
public void testDKIMSignMessageAsObjectNotConverted()
throws MessagingException, IOException, FailException {
MimeMessage mm = new MimeMessage(Session
.getDefaultInstance(new Properties()));
mm.addFrom(new Address[]{new InternetAddress("io@bago.org")});
mm.addRecipient(RecipientType.TO, new InternetAddress("io@bago.org"));
mm.setContent("An 8bit encoded body with \u20ACuro symbol.",
"text/plain; charset=iso-8859-15");
mm.setHeader("Content-Transfer-Encoding", "8bit");
mm.saveChanges();
FakeMailContext FakeMailContext = FAKE_MAIL_CONTEXT;
FakeMailContext.getServerInfo();
FakeMailetConfig mci = FakeMailetConfig.builder()
.mailetName("Test")
.mailetContext(FAKE_MAIL_CONTEXT)
.setProperty(
"signatureTemplate",
"v=1; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;")
.setProperty("privateKey", TESTING_PEM)
.build();
Mail mail = FakeMail.builder()
.mimeMessage(mm)
.build();
Mailet mailet = new DKIMSign();
mailet.init(mci);
Mailet m7bit = new ConvertTo7Bit();
m7bit.init(mci);
// m7bit.service(mail);
mailet.service(mail);
m7bit.service(mail);
ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
mail.getMessage().writeTo(rawMessage);
MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
"selector", "example.com");
try {
verify(rawMessage, mockPublicKeyRecordRetriever);
Assert.fail("Expected PermFail");
} catch (PermFailException e) {
}
}
}