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

Java tutorial

Introduction

Here is the source code for mitm.application.djigzo.james.mailets.SMIMESignTest.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.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.security.KeyStore;
import java.security.NoSuchProviderException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.mail.BodyPart;
import javax.mail.Multipart;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import mitm.application.djigzo.AutoTransactDelegator;
import mitm.application.djigzo.DjigzoTestUtils;
import mitm.application.djigzo.User;
import mitm.application.djigzo.james.mock.MockMail;
import mitm.application.djigzo.james.mock.MockMailetConfig;
import mitm.application.djigzo.service.SystemServices;
import mitm.application.djigzo.workflow.CertificateWorkflow;
import mitm.application.djigzo.workflow.KeyAndCertificateWorkflow;
import mitm.application.djigzo.workflow.UserWorkflow;
import mitm.common.hibernate.DatabaseActionExecutor;
import mitm.common.hibernate.DatabaseActionExecutorBuilder;
import mitm.common.hibernate.DatabaseException;
import mitm.common.hibernate.DatabaseVoidAction;
import mitm.common.hibernate.HibernateUtils;
import mitm.common.hibernate.SessionManager;
import mitm.common.mail.MailUtils;
import mitm.common.properties.HierarchicalPropertiesException;
import mitm.common.security.KeyAndCertificate;
import mitm.common.security.SecurityFactoryFactory;
import mitm.common.security.certificate.CertificateUtils;
import mitm.common.security.certificate.X509CertificateInspector;
import mitm.common.security.digest.Digest;
import mitm.common.security.keystore.KeyStoreProvider;
import mitm.common.security.smime.SMIMEHeader;
import mitm.common.security.smime.SMIMEInspector;
import mitm.common.security.smime.SMIMEInspectorImpl;
import mitm.common.security.smime.SMIMEType;
import mitm.common.security.smime.SMIMEUtils;
import mitm.common.util.BigIntegerUtils;

import org.apache.commons.lang.StringUtils;
import org.apache.mailet.MailAddress;
import org.hibernate.Session;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

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

    private static final File tempDir = new File("test/tmp");

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

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

        CertificateWorkflow rootWorkflow = SystemServices.getKeyAndRootCertificateWorkflow();

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

        addUser();
    }

    @Before
    public void before() throws Exception {
        KeyAndCertificateWorkflow keyAndCertificateWorkflow = SystemServices.getKeyAndCertificateWorkflow();

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

    private static void importKeyStore(KeyAndCertificateWorkflow keyAndCertificateWorkflow, File pfxFile)
            throws Exception {
        KeyStore keyStore = SecurityFactoryFactory.getSecurityFactory().createKeyStore("PKCS12");

        // initialize key store
        keyStore.load(new FileInputStream(pfxFile), "test".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);
            }
        }
    }

    private static void addUser() throws Exception {
        final SessionManager sessionManager = SystemServices.getSessionManager();

        Session previousSession = sessionManager.getSession();

        final File certificateFile = new File("test/resources/testdata/certificates/"
                + "Martijn_Brinkers_Comodo_Class_Security_Services_CA.pem.cer");

        try {
            DatabaseActionExecutor actionExecutor = DatabaseActionExecutorBuilder
                    .createDatabaseActionExecutor(sessionManager);

            actionExecutor.executeTransaction(new DatabaseVoidAction() {
                @Override
                public void doAction(Session session) throws DatabaseException {
                    sessionManager.setSession(session);

                    addUserAction(session, certificateFile);
                }
            });
        } finally {
            sessionManager.setSession(previousSession);
        }
    }

    public static void addUserAction(Session session, File certificateFile) throws DatabaseException {
        UserWorkflow userWorkflow = SystemServices.getUserWorkflow();

        try {
            User user = userWorkflow.addUser("m.brinkers@pobox.com");

            userWorkflow.makePersistent(user);

            Collection<? extends Certificate> certificates = CertificateUtils.readCertificates(certificateFile);

            for (Certificate certificate : certificates) {
                if (certificate instanceof X509Certificate) {
                    user.getUserPreferences().getCertificates().add((X509Certificate) certificate);
                }
            }
        } catch (AddressException e) {
            throw new DatabaseException(e);
        } catch (CertificateException e) {
            throw new DatabaseException(e);
        } catch (NoSuchProviderException e) {
            throw new DatabaseException(e);
        } catch (FileNotFoundException e) {
            throw new DatabaseException(e);
        } catch (HierarchicalPropertiesException e) {
            throw new DatabaseException(e);
        }
    }

    /*
     * Sign large message and test the performance
     */
    @Test
    public void testPerformanceTest() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        int repeat = 10;

        long start = System.currentTimeMillis();

        for (int i = 0; i < repeat; i++) {
            MockMail mail = new MockMail();

            MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/test-5120K.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);

            MailUtils.validateMessage(mail.getMessage());

            assertEquals(SMIMEHeader.DETACHED_SIGNATURE_TYPE,
                    SMIMEUtils.dissectSigned((Multipart) mail.getMessage().getContent())[1].getContentType());

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

            assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
            assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));

            List<X509Certificate> certificates = inspector.getSignedInspector().getCertificates();

            assertEquals(3, certificates.size());

            assertEquals("1C1C1CF46CC9233B23391A3B9BEF558969567091", X509CertificateInspector
                    .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
            assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                    .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
            assertEquals("69D7FFAF26BD5E9E4F42083BCA077BFAA8398593", X509CertificateInspector
                    .getThumbprint(inspector.getSignedInspector().getCertificates().get(2), Digest.SHA1));

            assertEquals(1, inspector.getSignedInspector().getSigners().size());
            assertEquals(Digest.SHA1.getOID(),
                    inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());
        }

        long diff = System.currentTimeMillis() - start;

        double perSecond = repeat * 1000.0 / diff;

        System.out.println("PDF ecryptions/sec: " + perSecond);

        /*
         * NOTE: !!! can fail on a slower system
         * 
         * On my Quad CPU Q8300, 100 repeats: 1.8/sec
         */
        assertTrue("S/MIME encryption too slow. !!! this can fail on a slower system !!!", perSecond > 1);
    }

    @Test
    public void testNewMessageID() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

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

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

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

        assertEquals("<123456>", 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);

        MailUtils.validateMessage(mail.getMessage());

        assertEquals(SMIMEHeader.DETACHED_SIGNATURE_TYPE,
                SMIMEUtils.dissectSigned((Multipart) mail.getMessage().getContent())[1].getContentType());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(3, inspector.getSignedInspector().getCertificates().size());
        assertEquals("1C1C1CF46CC9233B23391A3B9BEF558969567091", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
        assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
        assertEquals("69D7FFAF26BD5E9E4F42083BCA077BFAA8398593", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(2), Digest.SHA1));
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(Digest.SHA1.getOID(),
                inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());

        assertFalse("<123456>".equals(mail.getMessage().getMessageID()));
        assertTrue(mail.getMessage().getMessageID().contains("JavaMail"));
    }

    @Test
    public void testRetainMessageID() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

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

        assertEquals("<123456>", 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);

        MailUtils.validateMessage(mail.getMessage());

        assertEquals(SMIMEHeader.DETACHED_SIGNATURE_TYPE,
                SMIMEUtils.dissectSigned((Multipart) mail.getMessage().getContent())[1].getContentType());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(3, inspector.getSignedInspector().getCertificates().size());
        assertEquals("1C1C1CF46CC9233B23391A3B9BEF558969567091", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
        assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
        assertEquals("69D7FFAF26BD5E9E4F42083BCA077BFAA8398593", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(2), Digest.SHA1));
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(Digest.SHA1.getOID(),
                inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());

        assertEquals("<123456>", mail.getMessage().getMessageID());
    }

    @Test
    public void testDeprecatedContentType() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

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

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-message.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);

        MailUtils.validateMessage(mail.getMessage());

        assertEquals(SMIMEHeader.DEPRECATED_DETACHED_SIGNATURE_TYPE,
                SMIMEUtils.dissectSigned((Multipart) mail.getMessage().getContent())[1].getContentType());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(3, inspector.getSignedInspector().getCertificates().size());
        assertEquals("1C1C1CF46CC9233B23391A3B9BEF558969567091", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
        assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
        assertEquals("69D7FFAF26BD5E9E4F42083BCA077BFAA8398593", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(2), Digest.SHA1));
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(Digest.SHA1.getOID(),
                inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());
        assertNotNull(mail.getMessage().getMessageID());
    }

    @Test
    public void testInvalidFrom() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        mailetConfig.setInitParameter("catchRuntimeExceptions", "false");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

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

        message.setFrom(new InternetAddress("xxx"));

        message.saveChanges();

        mail.setMessage(message);

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

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

        mail.setRecipients(recipients);

        mail.setSender(null);

        mailet.service(mail);

        MailUtils.validateMessage(mail.getMessage());

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

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

    @Test
    public void testKeyMissing() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        mailetConfig.setInitParameter("catchRuntimeExceptions", "false");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-message.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);

        MailUtils.validateMessage(mail.getMessage());

        /*
         * Remove all keys from KeyStore and try to sign again.
         */
        KeyStoreProvider keyStoreService = SystemServices.getKeyStore();

        assertNotNull(keyStoreService);

        Enumeration<String> aliasEnum = keyStoreService.getKeyStore().aliases();

        while (aliasEnum.hasMoreElements()) {
            String alias = aliasEnum.nextElement();

            keyStoreService.getKeyStore().deleteEntry(alias);
        }

        mailet.service(mail);

        MailUtils.validateMessage(mail.getMessage());
    }

    @Test
    public void testUnknownContentTransferEncoding() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils
                .loadMessage(new File(testBase, "mail/unknown-content-transfer-encoding.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);

        MailUtils.validateMessage(mail.getMessage());
    }

    @Test
    public void testUnknownCharset() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/unknown-charset-xxx.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);

        MailUtils.validateMessage(mail.getMessage());

        //TODO: the message is not signed and not checked. Need to add fallback charset provider 
    }

    @Test
    public void testDefaultSettingsNoAddRoot() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        mailetConfig.setInitParameter("addRoot", "false");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-message.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);

        MailUtils.validateMessage(mail.getMessage());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(2, inspector.getSignedInspector().getCertificates().size());
        assertEquals("1C1C1CF46CC9233B23391A3B9BEF558969567091", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
        assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(Digest.SHA1.getOID(),
                inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());
    }

    @Test
    public void testDefaultSettings() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-message.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);

        MailUtils.validateMessage(mail.getMessage());

        MailUtils.writeMessage(mail.getMessage(), new File(tempDir, "testDefaultSettings.eml"));

        assertEquals(SMIMEHeader.DETACHED_SIGNATURE_TYPE,
                SMIMEUtils.dissectSigned((Multipart) mail.getMessage().getContent())[1].getContentType());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(3, inspector.getSignedInspector().getCertificates().size());
        assertEquals("1C1C1CF46CC9233B23391A3B9BEF558969567091", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
        assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
        assertEquals("69D7FFAF26BD5E9E4F42083BCA077BFAA8398593", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(2), Digest.SHA1));
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(Digest.SHA1.getOID(),
                inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());

        // check that no headers are signed. Only a content-type header should be added to the part
        Multipart mp = (Multipart) mail.getMessage().getContent();

        assertEquals(2, mp.getCount());

        BodyPart part = mp.getBodyPart(0);

        Enumeration<?> e = part.getNonMatchingHeaders(new String[] { "content-type" });

        assertFalse(e.hasMoreElements());
    }

    @Test
    public void testSenderCaseInsensitive() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-message.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);

        MailUtils.validateMessage(mail.getMessage());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(3, inspector.getSignedInspector().getCertificates().size());
        assertEquals("1C1C1CF46CC9233B23391A3B9BEF558969567091", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
        assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
        assertEquals("69D7FFAF26BD5E9E4F42083BCA077BFAA8398593", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(2), Digest.SHA1));
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(Digest.SHA1.getOID(),
                inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());
    }

    @Test
    public void testSHA512Opaque() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        mailetConfig.setInitParameter("algorithm", "SHA512WithRSA");
        mailetConfig.setInitParameter("signMode", "opaque");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-message.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);

        MailUtils.validateMessage(mail.getMessage());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.OPAQUE_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(3, inspector.getSignedInspector().getCertificates().size());
        assertEquals("1C1C1CF46CC9233B23391A3B9BEF558969567091", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
        assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
        assertEquals("69D7FFAF26BD5E9E4F42083BCA077BFAA8398593", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(2), Digest.SHA1));
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(Digest.SHA512.getOID(),
                inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());
    }

    /*
     * Checks if setting catchRuntimeExceptions and catchErrors is allowed
     */
    @Test
    public void testSetBaseParameters() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        mailetConfig.setInitParameter("catchRuntimeExceptions", "true");
        mailetConfig.setInitParameter("catchErrors", "true");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);
    }

    @Test
    public void testProtectedHeaders() throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

        mailetConfig.setInitParameter("protectedHeader", "subject,to,from");

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-message.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);

        MailUtils.validateMessage(mail.getMessage());

        MailUtils.writeMessage(mail.getMessage(), new File(tempDir, "testProtectedHeaders.eml"));

        assertEquals(SMIMEHeader.DETACHED_SIGNATURE_TYPE,
                SMIMEUtils.dissectSigned((Multipart) mail.getMessage().getContent())[1].getContentType());

        // check if some headers are signed
        Multipart mp = (Multipart) mail.getMessage().getContent();

        assertEquals(2, mp.getCount());

        BodyPart part = mp.getBodyPart(0);

        // there should be 3 non content-type headers
        Enumeration<?> e = part.getNonMatchingHeaders(new String[] { "content-type" });

        int count = 0;
        while (e.hasMoreElements()) {
            e.nextElement();
            count++;
        }
        assertEquals(3, count);

        assertEquals("test simple message", StringUtils.join(part.getHeader("subject"), ","));
        assertEquals("test@example.com", StringUtils.join(part.getHeader("from"), ","));
        assertEquals("test@example.com", StringUtils.join(part.getHeader("to"), ","));
    }

    @Test
    public void testSignBuildPath() throws Exception {
        AutoTransactDelegator proxy = AutoTransactDelegator.createProxy();

        /*
         * Find a certificate with critical EMAILPROTECTION extension
         */
        X509CertSelector selector = new X509CertSelector();

        selector.setSerialNumber(BigIntegerUtils.hexDecode("1178C3B653829E895ACB7100EB1F627"));
        selector.setIssuer("EMAILADDRESS=ca@example.com, CN=MITM Test CA, L=Amsterdam, ST=NH, C=NL");

        List<KeyAndCertificate> keyAndCertificates = proxy.getKeyAndCertificates(selector);

        assertEquals(1, keyAndCertificates.size());

        proxy.setUserSigningKeyAndCertificate("test@example.com", keyAndCertificates.get(0));

        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

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

        mail.setMessage(message);

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

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

        mail.setRecipients(recipients);

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

        mailet.service(mail);

        MailUtils.validateMessage(mail.getMessage());

        MailUtils.writeMessage(mail.getMessage(), new File(tempDir, "testDefaultSettings.eml"));

        assertEquals(SMIMEHeader.DETACHED_SIGNATURE_TYPE,
                SMIMEUtils.dissectSigned((Multipart) mail.getMessage().getContent())[1].getContentType());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(3, inspector.getSignedInspector().getCertificates().size());
        assertEquals("F18CC8973F9AB82A6C47448282849A72416B6DAB", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(0), Digest.SHA1));
        assertEquals("D8F8E5B92E651B1E3EF93B5493EACDE4C13AFEE0", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(1), Digest.SHA1));
        assertEquals("69D7FFAF26BD5E9E4F42083BCA077BFAA8398593", X509CertificateInspector
                .getThumbprint(inspector.getSignedInspector().getCertificates().get(2), Digest.SHA1));
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(Digest.SHA1.getOID(),
                inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());

        // check that no headers are signed. Only a content-type header should be added to the part
        Multipart mp = (Multipart) mail.getMessage().getContent();

        assertEquals(2, mp.getCount());

        BodyPart part = mp.getBodyPart(0);

        Enumeration<?> e = part.getNonMatchingHeaders(new String[] { "content-type" });

        assertFalse(e.hasMoreElements());
    }

    public void sign(String signingAlgorithm, String digestOID) throws Exception {
        MockMailetConfig mailetConfig = new MockMailetConfig("test");

        mailetConfig.setInitParameter("algorithmAttribute", "signingAlgo");

        SMIMESign mailet = new SMIMESign();

        mailet.init(mailetConfig);

        MockMail mail = new MockMail();

        MimeMessage message = MailUtils.loadMessage(new File(testBase, "mail/simple-text-message.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"));

        mail.setAttribute("signingAlgo", signingAlgorithm);

        mailet.service(mail);

        MailUtils.validateMessage(mail.getMessage());

        MailUtils.writeMessage(mail.getMessage(), new File(tempDir, "testDefaultSettings.eml"));

        assertEquals(SMIMEHeader.DETACHED_SIGNATURE_TYPE,
                SMIMEUtils.dissectSigned((Multipart) mail.getMessage().getContent())[1].getContentType());

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

        assertEquals(SMIMEType.SIGNED, inspector.getSMIMEType());
        assertEquals(SMIMEHeader.Type.CLEAR_SIGNED, SMIMEHeader.getSMIMEContentType(mail.getMessage()));
        assertEquals(3, inspector.getSignedInspector().getCertificates().size());
        assertEquals(1, inspector.getSignedInspector().getSigners().size());
        assertEquals(digestOID, inspector.getSignedInspector().getSigners().get(0).getDigestAlgorithmOID());

        // check that no headers are signed. Only a content-type header should be added to the part
        Multipart mp = (Multipart) mail.getMessage().getContent();

        assertEquals(2, mp.getCount());

        BodyPart part = mp.getBodyPart(0);

        Enumeration<?> e = part.getNonMatchingHeaders(new String[] { "content-type" });

        assertFalse(e.hasMoreElements());
    }

    @Test
    public void testSigningAlgorithmAttribute() throws Exception {
        sign("MD2WITHRSA", "1.2.840.113549.2.2");
        sign("MD5WITHRSA", Digest.MD5.getOID());
        sign("SHA1WITHRSAENCRYPTION", Digest.SHA1.getOID());
        sign("SHA224WITHRSAENCRYPTION", Digest.SHA224.getOID());
        sign("SHA256WITHRSA", Digest.SHA256.getOID());
        sign("SHA384WITHRSAENCRYPTION", Digest.SHA384.getOID());
        sign("SHA512WITHRSA", Digest.SHA512.getOID());
        sign("RIPEMD160WITHRSA", Digest.RIPEMD160.getOID());
        sign("RIPEMD128WITHRSA", Digest.RIPEMD128.getOID());
        sign("RIPEMD256WITHRSA", Digest.RIPEMD256.getOID());
    }
}