mitm.application.djigzo.james.mailets.SMIMEHandlerTest.java Source code

Java tutorial

Introduction

Here is the source code for mitm.application.djigzo.james.mailets.SMIMEHandlerTest.java

Source

/*
 * 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 static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

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

import mitm.application.djigzo.AutoTransactDelegator;
import mitm.application.djigzo.DjigzoTestUtils;
import mitm.application.djigzo.james.DjigzoMailAttributesImpl;
import mitm.application.djigzo.james.SecurityInfoTags;
import mitm.application.djigzo.james.mock.MockMail;
import mitm.application.djigzo.james.mock.MockMailetConfig;
import mitm.application.djigzo.james.mock.SendMailEventListener;
import mitm.application.djigzo.james.mock.SendMailEventListenerImpl;
import mitm.application.djigzo.service.SystemServices;
import mitm.application.djigzo.workflow.CertificateWorkflow;
import mitm.application.djigzo.workflow.KeyAndCertificateWorkflow;
import mitm.common.hibernate.HibernateUtils;
import mitm.common.mail.MailUtils;
import mitm.common.security.SecurityConstants;
import mitm.common.security.SecurityFactoryFactory;
import mitm.common.security.certificate.CertificateUtils;
import mitm.common.security.ctl.CTLEntryStatus;
import mitm.common.security.smime.SMIMEInspector;
import mitm.common.security.smime.SMIMEInspectorImpl;
import mitm.common.security.smime.SMIMEType;
import mitm.common.util.FileConstants;
import mitm.test.TestUtils;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.mailet.Mail;
import org.apache.mailet.MailAddress;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class SMIMEHandlerTest {
    private final static File testBase = new File("test/resources/testdata");

    private static KeyAndCertificateWorkflow keyAndCertificateWorkflow;

    private MockMailetConfig mailetConfig;

    private SendMailEventListener sendMailEventListener;

    private static int tempFileCount;

    private static KeyStore keyStore;

    private static AutoTransactDelegator proxy;

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        DjigzoTestUtils.initialize();

        HibernateUtils.recreateTables(SystemServices.getHibernateSessionSource().getHibernateConfiguration());

        keyAndCertificateWorkflow = SystemServices.getKeyAndCertificateWorkflow();

        proxy = AutoTransactDelegator.createProxy();
    }

    @Before
    public void before() throws Exception {
        proxy.deleteAllUsers();
        proxy.deleteAllDomains();
        proxy.cleanCTL();

        CertificateWorkflow rootWorkflow = SystemServices.getKeyAndRootCertificateWorkflow();

        importKeyStore(keyAndCertificateWorkflow, new File("test/resources/testdata/keys/testCertificates.p12"),
                "test");

        importCertificates(rootWorkflow, new File("test/resources/testdata/certificates/mitm-test-root.cer"));

        mailetConfig = new MockMailetConfig("test");

        sendMailEventListener = new SendMailEventListenerImpl();

        mailetConfig.getMailetContext().setSendMailEventListener(sendMailEventListener);

        // get the current nr of temp files
        tempFileCount = TestUtils.getTempFileCount(FileConstants.TEMP_FILE_PREFIX, ".tmp");
    }

    @After
    public void after() throws IOException {
        // check if we have any temp file leakage
        assertEquals(tempFileCount, TestUtils.getTempFileCount(FileConstants.TEMP_FILE_PREFIX, ".tmp"));
    }

    private static void importKeyStore(KeyAndCertificateWorkflow keyAndCertificateWorkflow, File pfxFile,
            String password) throws Exception {
        proxy.cleanKeyAndCertStore();
        proxy.cleanKeyAndRootStore();

        keyStore = SecurityFactoryFactory.getSecurityFactory().createKeyStore("PKCS12");

        // initialize key store
        keyStore.load(new FileInputStream(pfxFile), password.toCharArray());

        keyAndCertificateWorkflow.importKeyStore(keyStore, KeyAndCertificateWorkflow.MissingKey.ADD_CERTIFICATE);
    }

    private static void importCertificates(CertificateWorkflow rootWorkflow, File certificateFile)
            throws Exception {
        Collection<? extends Certificate> certificates = CertificateUtils.readCertificates(certificateFile);

        for (Certificate certificate : certificates) {
            if (certificate instanceof X509Certificate) {
                rootWorkflow.addCertificateTransacted((X509Certificate) certificate);
            }
        }
    }

    @Test
    public void testDecompress() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("threshold", "0");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-body-compressed.eml"));

        mail.setMessage(message);

        SMIMEInspector inspector = new SMIMEInspectorImpl(mail.getMessage(), null, "BC");

        assertEquals(SMIMEType.COMPRESSED, inspector.getSMIMEType());

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.NONE, inspector.getSMIMEType());

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void testNoDecompress() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("decompress", "false");
        mailetConfig.setInitParameter("threshold", "0");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState("abc");

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-body-compressed.eml"));

        mail.setMessage(message);

        SMIMEInspector inspector = new SMIMEInspectorImpl(mail.getMessage(), null, "BC");

        assertEquals(SMIMEType.COMPRESSED, inspector.getSMIMEType());

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(0, sendMailEventListener.getMails().size());

        inspector = new SMIMEInspectorImpl(mail.getMessage(), null, "BC");

        assertEquals(SMIMEType.COMPRESSED, inspector.getSMIMEType());

        assertEquals(message, mail.getMessage());

        assertEquals("abc", mail.getState());
        assertEquals("[m.brinkers@pobox.com]", ObjectUtils.toString(mail.getRecipients()));
    }

    @Test
    public void testDefaultSettings() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        assertEquals("<602167900.17.1194204767299.JavaMail.martijn@ubuntu>", message.getMessageID());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        assertEquals(22, proxy.getKeyAndCertStoreSize());

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());

        assertEquals("<602167900.17.1194204767299.JavaMail.martijn@ubuntu>", newMail.getMessage().getMessageID());

        assertEquals(Mail.GHOST, mail.getState());

        /*
         * certs should have been added
         */
        assertEquals(25, proxy.getKeyAndCertStoreSize());
    }

    @Test
    public void testNewMessageID() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("retainMessageID", "false");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        assertEquals("<602167900.17.1194204767299.JavaMail.martijn@ubuntu>", message.getMessageID());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());

        assertFalse(
                "<602167900.17.1194204767299.JavaMail.martijn@ubuntu>".equals(newMail.getMessage().getMessageID()));

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void testRemoveSignature() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("removeSignature", "true");
        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        assertEquals("<602167900.17.1194204767299.JavaMail.martijn@ubuntu>", message.getMessageID());

        mail.setMessage(message);

        SMIMEInspector inspector = new SMIMEInspectorImpl(mail.getMessage(), null, "BC");

        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertEquals("handled", newMail.getState());

        inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.NONE, inspector.getSMIMEType());

        assertEquals("<602167900.17.1194204767299.JavaMail.martijn@ubuntu>", newMail.getMessage().getMessageID());

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void testNoDecrypt() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("removeSignature", "true");
        mailetConfig.setInitParameter("decrypt", "false");
        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("threshold", "0");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        mail.setMessage(message);

        SMIMEInspector inspector = new SMIMEInspectorImpl(mail.getMessage(), null, "BC");

        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(0, sendMailEventListener.getMails().size());

        inspector = new SMIMEInspectorImpl(mail.getMessage(), null, "BC");

        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        assertEquals(message, mail.getMessage());
    }

    /*
     * Checks if setting catchRuntimeExceptions and catchErrors is allowed
     */
    @Test
    public void testSetBaseParameters() throws Exception {
        mailetConfig.setInitParameter("catchRuntimeExceptions", "true");
        mailetConfig.setInitParameter("catchErrors", "true");
        mailetConfig.setInitParameter("handledProcessor", "handled");

        SMIMEHandler mailet = new SMIMEHandler();

        mailet.init(mailetConfig);
    }

    /*
     * Checks for missing handledProcessor
     */
    @Test(expected = MessagingException.class)
    public void testMissingHandledProcessor() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailet.init(mailetConfig);
    }

    @Test
    public void testDecryptOL2010WithMissingSKIInSubjectWorkaroundEnabled() throws Exception {
        boolean skiWorkaroundEnabled = SecurityConstants.isOutlook2010SKIWorkaroundEnabled();

        try {
            SecurityConstants.setOutlook2010SKIWorkaroundEnabled(true);

            importKeyStore(keyAndCertificateWorkflow,
                    new File("test/resources/testdata/keys/outlook2010_cert_missing_subjkeyid.p12"), "");

            SMIMEHandler mailet = new SMIMEHandler();

            mailetConfig.setInitParameter("handledProcessor", "handled");

            mailet.init(mailetConfig);

            MockMail mail = new MockMail();

            MimeMessage message = MailUtils
                    .loadMessage(new File(testBase, "mail/outlook2010_cert_missing_subjkeyid.eml"));

            mail.setMessage(message);

            Set<MailAddress> recipients = new HashSet<MailAddress>();

            recipients.add(new MailAddress("m.brinkers@pobox.com"));

            mail.setRecipients(recipients);

            mail.setSender(new MailAddress("test@example.com"));

            mailet.service(mail);

            assertEquals(1, sendMailEventListener.getMails().size());

            Mail newMail = sendMailEventListener.getMails().get(0);

            MimeMessage decrypted = newMail.getMessage();

            assertTrue(decrypted.isMimeType("text/plain"));
            assertEquals("A broken S/MIME encrypted message", decrypted.getSubject());
            assertEquals("<000c01cadd1e$d8e3b700$8aab2500$@Domain>", decrypted.getMessageID());
            assertEquals(message.getMessageID(), decrypted.getMessageID());
            assertEquals("3DES, Key size: 168", decrypted.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
            assertEquals("//2219E504D5750B37D20CC930B14129E1A2E583B1/1.2.840.113549.1.1.1",
                    decrypted.getHeader("X-Djigzo-Info-Encryption-Recipient-0-0", ","));
            assertEquals("Created with Outlook 2010 Beta (14.0.4536.1000)",
                    StringUtils.trim((String) decrypted.getContent()));

            assertEquals(Mail.GHOST, mail.getState());
        } finally {
            SecurityConstants.setOutlook2010SKIWorkaroundEnabled(skiWorkaroundEnabled);
        }
    }

    @Test
    public void testDecryptOL2010WithMissingSKIInSubjectWorkaroundDisabledDefault() throws Exception {
        importKeyStore(keyAndCertificateWorkflow,
                new File("test/resources/testdata/keys/outlook2010_cert_missing_subjkeyid.p12"), "");

        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState("s1");

        MimeMessage message = MailUtils
                .loadMessage(new File(testBase, "mail/outlook2010_cert_missing_subjkeyid.eml"));

        mail.setMessage(message);

        assertTrue(mail.getMessage().isMimeType("application/pkcs7-mime"));

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));
        recipients.add(new MailAddress("test@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertTrue(newMail.getMessage().isMimeType("application/pkcs7-mime"));

        assertEquals(2, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("m.brinkers@pobox.com")));

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void testStrictMultipleRecipients() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("strict", "true");
        mailetConfig.setInitParameter("threshold", "10");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState(Mail.TRANSPORT);

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/encrypt-15-recipients.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("test@example.com"));
        recipients.add(new MailAddress("test2@example.com"));
        recipients.add(new MailAddress("test3@example.com"));
        recipients.add(new MailAddress("test4@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("sender@example.com"));

        mailet.service(mail);

        assertEquals(2, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.NONE, inspector.getSMIMEType());

        assertEquals(3, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test2@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test3@example.com")));
        assertEquals("handled", newMail.getState());

        newMail = sendMailEventListener.getMails().get(1);

        inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test4@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void testStrictSignedCorrupt() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("strict", "true");
        mailetConfig.setInitParameter("threshold", "10");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState(Mail.TRANSPORT);

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-opaque-corrupt.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("test@example.com"));
        recipients.add(new MailAddress("test2@example.com"));
        recipients.add(new MailAddress("test3@example.com"));
        recipients.add(new MailAddress("test4@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("sender@example.com"));

        mailet.service(mail);

        assertEquals(0, sendMailEventListener.getMails().size());

        assertEquals(4, mail.getRecipients().size());
        assertTrue(mail.getRecipients().contains(new MailAddress("test@example.com")));
        assertTrue(mail.getRecipients().contains(new MailAddress("test2@example.com")));
        assertTrue(mail.getRecipients().contains(new MailAddress("test3@example.com")));
        assertTrue(mail.getRecipients().contains(new MailAddress("test4@example.com")));

        assertEquals(Mail.TRANSPORT, mail.getState());
    }

    @Test
    public void testRemoveSignatureMailAttribute() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("removeSignatureAttribute", "attr.removeSignature");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        assertEquals("<602167900.17.1194204767299.JavaMail.martijn@ubuntu>", message.getMessageID());

        mail.setMessage(message);
        mail.setAttribute("attr.removeSignature", "true");

        SMIMEInspector inspector = new SMIMEInspectorImpl(mail.getMessage(), null, "BC");

        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertEquals("handled", newMail.getState());

        inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.NONE, inspector.getSMIMEType());

        assertEquals("<602167900.17.1194204767299.JavaMail.martijn@ubuntu>", newMail.getMessage().getMessageID());

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void testStrictMailAttribute() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("threshold", "10");
        mailetConfig.setInitParameter("strictAttribute", "attr.strict");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setAttribute("attr.strict", "true");

        mail.setState(Mail.TRANSPORT);

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/encrypt-15-recipients.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("test@example.com"));
        recipients.add(new MailAddress("test2@example.com"));
        recipients.add(new MailAddress("test3@example.com"));
        recipients.add(new MailAddress("test4@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("sender@example.com"));

        mailet.service(mail);

        assertEquals(2, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.NONE, inspector.getSMIMEType());

        assertEquals(3, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test2@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test3@example.com")));
        assertEquals("handled", newMail.getState());

        newMail = sendMailEventListener.getMails().get(1);

        inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test4@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void test3Layers() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("threshold", "10");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState(Mail.TRANSPORT);

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/3-layer-encrypted.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("test@example.com"));
        recipients.add(new MailAddress("test2@example.com"));
        recipients.add(new MailAddress("test3@example.com"));
        recipients.add(new MailAddress("test4@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("sender@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        MimeMessage newMessage = newMail.getMessage();

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        assertEquals(SMIMEType.NONE, inspector.getSMIMEType());

        assertEquals(4, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test2@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test3@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test4@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals(Mail.GHOST, mail.getState());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-1", ","));
        assertEquals("AES128, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-2", ","));

        assertEquals("test", ((String) newMessage.getContent()).trim());
    }

    @Test
    public void test3LayersStrict() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("threshold", "10");
        mailetConfig.setInitParameter("strictAttribute", "attr.strict");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setAttribute("attr.strict", true);

        mail.setState(Mail.TRANSPORT);

        /*
         * message with 3 layers of encryption
         */
        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/3-layer-encrypted.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("test@example.com"));
        recipients.add(new MailAddress("test2@example.com"));
        recipients.add(new MailAddress("test3@example.com"));
        recipients.add(new MailAddress("test4@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("sender@example.com"));

        mailet.service(mail);

        assertEquals(3, sendMailEventListener.getMails().size());

        /* message 1 */

        Mail newMail = sendMailEventListener.getMails().get(0);

        MimeMessage newMessage = newMail.getMessage();

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the last layer could not be decrypted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * Only test@example.com can decrypt the first two layers
         */
        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-1", ","));
        assertEquals("AES128, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-2", ","));

        /* message 2 */

        newMail = sendMailEventListener.getMails().get(1);

        newMessage = newMail.getMessage();

        inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the last layer could not be decrypted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * test2@example.com and test3@example.com can only decrypt the first layers
         */
        assertEquals(2, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test2@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test3@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-1", ","));
        assertNull(newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-2"));

        newMail = sendMailEventListener.getMails().get(2);

        newMessage = newMail.getMessage();

        inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the last message could not be decrypted beause of strict mode
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test4@example.com")));

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void test3LayersStrictWithExplicitCertificate() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("threshold", "10");
        mailetConfig.setInitParameter("strictAttribute", "attr.strict");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setAttribute("attr.strict", true);

        mail.setState(Mail.TRANSPORT);

        /*
         * Make sure sub@subdomain.example.com can decrypt all
         */
        proxy.addUserCertificate("sub@subdomain.example.com", (X509Certificate) keyStore.getCertificate("NoEmail"));
        proxy.addUserCertificate("sub@subdomain.example.com",
                (X509Certificate) keyStore.getCertificate("ValidCertificate"));
        proxy.addUserCertificate("sub@subdomain.example.com",
                (X509Certificate) keyStore.getCertificate("multipleEmail"));

        /*
         * message with 3 layers of encryption
         */
        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/3-layer-encrypted.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new LinkedHashSet<MailAddress>();

        recipients.add(new MailAddress("test@example.com"));
        recipients.add(new MailAddress("test2@example.com"));
        recipients.add(new MailAddress("test3@example.com"));
        recipients.add(new MailAddress("test4@example.com"));
        recipients.add(new MailAddress("sub@subdomain.example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("sender@example.com"));

        mailet.service(mail);

        assertEquals(4, sendMailEventListener.getMails().size());

        /* message 1 */

        Mail newMail = sendMailEventListener.getMails().get(0);

        MimeMessage newMessage = newMail.getMessage();

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the last layer could not be decrypted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * Only test@example.com can decrypt the first two layers
         */
        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-1", ","));
        assertEquals("AES128, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-2", ","));

        /* message 2 */

        newMail = sendMailEventListener.getMails().get(1);

        newMessage = newMail.getMessage();

        inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the last layer could not be decrypted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * test2@example.com and test3@example.com can only decrypt the first layers
         */
        assertEquals(2, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test2@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test3@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-1", ","));
        assertNull(newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-2"));

        /* message 3 */

        newMail = sendMailEventListener.getMails().get(2);

        newMessage = newMail.getMessage();

        inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the last layer was also decrypted
         */
        assertEquals(SMIMEType.NONE, inspector.getSMIMEType());

        /*
         * sub@subdomain.example.com can decrypt all layers
         */
        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("sub@subdomain.example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-1", ","));
        assertEquals("AES128, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-2", ","));

        assertEquals("test", ((String) newMessage.getContent()).trim());

        newMail = sendMailEventListener.getMails().get(3);

        newMessage = newMail.getMessage();

        inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the last layer was also decrypted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * sub@subdomain.example.com can decrypt all layers
         */
        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test4@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void test3LayersStrictDomainCerts() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("threshold", "10");
        mailetConfig.setInitParameter("strict", "true");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState(Mail.TRANSPORT);

        /*
         * Make sure sub@subdomain.example.com can decrypt all
         */
        proxy.addDomainCertificate("sub.example.com", (X509Certificate) keyStore.getCertificate("NoEmail"));
        proxy.addDomainCertificate("sub.example.com",
                (X509Certificate) keyStore.getCertificate("ValidCertificate"));
        proxy.addDomainCertificate("sub.example.com", (X509Certificate) keyStore.getCertificate("multipleEmail"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/3-layer-encrypted.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new LinkedHashSet<MailAddress>();

        recipients.add(new MailAddress("test@sub.example.com"));
        recipients.add(new MailAddress("test2@sub.example.com"));
        recipients.add(new MailAddress("test3@sub.example.com"));
        recipients.add(new MailAddress("test4@sub.example.com"));
        recipients.add(new MailAddress("test5@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("sender@example.com"));

        mailet.service(mail);

        assertEquals(2, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        MimeMessage newMessage = newMail.getMessage();

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));

        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test5@example.com")));

        newMail = sendMailEventListener.getMails().get(1);

        newMessage = newMail.getMessage();

        inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        assertEquals(SMIMEType.NONE, inspector.getSMIMEType());

        assertEquals(4, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test@sub.example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test2@sub.example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test3@sub.example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test4@sub.example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-1", ","));
        assertEquals("AES128, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-2", ","));

        assertEquals("test", ((String) newMessage.getContent()).trim());

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void test3LayersStrictBlacklistedCert() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("threshold", "10");
        mailetConfig.setInitParameter("strict", "true");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState(Mail.TRANSPORT);

        /*
         * Blacklist the ValidCertificate
         */
        proxy.addToCTL((X509Certificate) keyStore.getCertificate("ValidCertificate"), CTLEntryStatus.BLACKLISTED,
                false);

        /*
         * message with 3 layers of encryption
         */
        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/3-layer-encrypted.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("test@example.com"));
        recipients.add(new MailAddress("test2@example.com"));
        recipients.add(new MailAddress("test3@example.com"));
        recipients.add(new MailAddress("test4@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("sender@example.com"));

        mailet.service(mail);

        assertEquals(2, sendMailEventListener.getMails().size());

        /* message 1 */

        Mail newMail = sendMailEventListener.getMails().get(0);

        MimeMessage newMessage = newMail.getMessage();

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the next layer could not be decrypted by test@example.com because valid certificate is blacklisted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * test@example.com, test2@example.com and test3@example.com can decrypt the first two layers
         */
        assertEquals(3, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test2@example.com")));
        assertTrue(newMail.getRecipients().contains(new MailAddress("test3@example.com")));
        assertEquals("handled", newMail.getState());

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-1", ","));
        assertNull(newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-2"));

        newMail = sendMailEventListener.getMails().get(1);

        newMessage = newMail.getMessage();

        inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * not decrypted by test4@example.com because of strict mode
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        assertEquals(1, newMail.getRecipients().size());
        assertTrue(newMail.getRecipients().contains(new MailAddress("test4@example.com")));

        assertEquals("RC2, Key size: 128", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));

        /*
         * test4@example.com is not allowed to decrypt the message
         */
        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void testNoDecryptionKey() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState("test");

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/encrypted-no-decryption-key.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("aap@noot.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        /*
         * With non strict mode, the message is always handled if it's an S/MIME message because
         * the security info is added
         */
        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        MimeMessage newMessage = newMail.getMessage();

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the message could not be decrypted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * Security information should be added
         */
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));

        assertEquals(Mail.GHOST, mail.getState());
    }

    @Test
    public void testNoDecryptionKeyStrict() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailetConfig.setInitParameter("strict", "true");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState("test");

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/encrypted-no-decryption-key.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("aap@noot.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        /*
         * in strict mode, the message is handled if the recipient has no keys but not decrypted
         */
        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        MimeMessage newMessage = newMail.getMessage();

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the message could not be decrypted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * Security information should be added
         */
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));

        assertEquals(Mail.GHOST, mail.getState());
    }

    /*
     * Test for bug https://jira.djigzo.com/browse/GATEWAY-27
     */
    @Test
    public void testSignedRecipientNoKeyStrict() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailetConfig.setInitParameter("strict", "true");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        mail.setState("test");

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/clear-signed-validcertificate.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("aap@noot.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        assertEquals(22, proxy.getKeyAndCertStoreSize());

        mailet.service(mail);

        /*
         * Signing cert should have been added
         */
        assertEquals(25, proxy.getKeyAndCertStoreSize());

        /*
         * in strict mode, the message is not handled if the recipient has no keys and the message is
         * encrypted. Signed message however *must* be handled even if the recipient has no key
         */
        assertEquals(1, sendMailEventListener.getMails().size());

        SMIMEInspector inspector = new SMIMEInspectorImpl(mail.getMessage(), null, "BC");

        /*
         * the message is still signed
         */
        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
    }

    @Test
    public void testNoImportCertificates() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("importCertificates", "false");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        SMIMEInspector inspector = new SMIMEInspectorImpl(message, null, "BC");

        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        assertEquals(22, proxy.getKeyAndCertStoreSize());

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());

        assertEquals(Mail.GHOST, mail.getState());

        /*
         * No certs should have been added
         */
        assertEquals(22, proxy.getKeyAndCertStoreSize());
    }

    @Test
    public void testAddSecurityInfoToSubject() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[%s decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());

        assertEquals("normal message with attachment [%s decrypted] [signed]", newMail.getMessage().getSubject());
    }

    @Test
    public void testAddSecurityInfoToSubjectStrict() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("strict", "true");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("test@example.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMail.getMessage(), null, "BC");

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());

        assertEquals("normal message with attachment [decrypted] [signed]", newMail.getMessage().getSubject());
    }

    @Test
    public void testAddSecurityInfoToSubject3Layers() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/3-layer-encrypted.eml"));

        assertEquals("test simple message", message.getSubject());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertEquals("test simple message [decrypted] [decrypted] [decrypted]", newMail.getMessage().getSubject());
    }

    @Test
    public void testAddSecurityInfoToSubject3NoDecryptionKey() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/encrypted-no-decryption-key.eml"));

        assertEquals("RE: Test ", message.getSubject());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("aap@noot.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        /*
         * With non strict mode, the message is always handled if it's an S/MIME message because
         * the security info is added
         */
        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        MimeMessage newMessage = newMail.getMessage();

        SMIMEInspector inspector = new SMIMEInspectorImpl(newMessage, null, "BC");

        /*
         * the message could not be decrypted
         */
        assertEquals(SMIMEType.ENCRYPTED, inspector.getSMIMEType());

        /*
         * Security information should be added
         */
        assertEquals("3DES, Key size: 168", newMessage.getHeader("X-Djigzo-Info-Encryption-Algorithm-0", ","));

        assertEquals("RE: Test ", newMail.getMessage().getSubject());
    }

    @Test
    public void testAddSecurityInfoToSubjectClearSigned() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-body-clear-signed.eml"));

        assertEquals("test simple message", message.getSubject());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertEquals("test simple message [signed]", newMail.getMessage().getSubject());
    }

    @Test
    public void testAddSecurityInfoToSubjectTampered() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/clear-signed-tampered.eml"));

        assertEquals("ik ook wipjam?", message.getSubject());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertEquals("ik ook wipjam? [invalid]", newMail.getMessage().getSubject());
    }

    @Test
    public void testAddSecurityInfoToSubjectInvalid() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils
                .loadMessage(new File(testBase, "mail/clear-sign-missing-smime-ext-key-usage.eml"));

        assertEquals("test simple message", message.getSubject());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertEquals("test simple message [invalid]", newMail.getMessage().getSubject());
    }

    @Test
    public void testAddSecurityInfoToSubjectSubjectTemplate() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");
        mailetConfig.setInitParameter("subjectTemplate", "%2$s ABC %1$s");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/signed-encrypt-validcertificate.eml"));

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertEquals("[signed] ABC [decrypted] ABC normal message with attachment",
                newMail.getMessage().getSubject());
    }

    @Test
    public void testAddSecurityInfoToSubjectMismatch() throws Exception {
        SMIMEHandler mailet = new SMIMEHandler();

        mailetConfig.setInitParameter("handledProcessor", "handled");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        DjigzoMailAttributesImpl.getInstance(mail).setSecurityInfoTags(
                new SecurityInfoTags("[decrypted]", "[signed]", "[signed by: %s]", "[invalid]"));

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-body-clear-signed.eml"));

        message.setFrom(new InternetAddress("sender@example.com"));

        assertEquals("test simple message", message.getSubject());

        mail.setMessage(message);

        Set<MailAddress> recipients = new HashSet<MailAddress>();

        recipients.add(new MailAddress("m.brinkers@pobox.com"));

        mail.setRecipients(recipients);

        mail.setSender(new MailAddress("test@example.com"));

        mailet.service(mail);

        assertEquals(1, sendMailEventListener.getMails().size());

        Mail newMail = sendMailEventListener.getMails().get(0);

        assertEquals("test simple message [signed by: test@example.com]", newMail.getMessage().getSubject());
    }
}