Java tutorial
/* * Copyright (c) 2008-2012, Martijn Brinkers, Djigzo. * * This file is part of Djigzo email encryption. * * Djigzo is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License * version 3, 19 November 2007 as published by the Free Software * Foundation. * * Djigzo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public * License along with Djigzo. If not, see <http://www.gnu.org/licenses/> * * Additional permission under GNU AGPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, * wsdl4j-1.6.1.jar (or modified versions of these libraries), * containing parts covered by the terms of Eclipse Public License, * tyrex license, freemarker license, dom4j license, mx4j license, * Spice Software License, Common Development and Distribution License * (CDDL), Common Public License (CPL) the licensors of this Program grant * you additional permission to convey the resulting work. */ package mitm.common.security.cms; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.math.BigInteger; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.PrivateKey; import java.security.cert.CertificateException; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; import javax.security.auth.x500.X500Principal; import mitm.common.mail.MailUtils; import mitm.common.security.KeyIdentifier; import mitm.common.security.SecurityFactory; import mitm.common.security.SecurityFactoryFactory; import mitm.common.security.bouncycastle.InitializeBouncycastle; import mitm.common.security.keystore.KeyStoreKeyProvider; import mitm.common.security.smime.SMIMEEncryptionAlgorithm; import mitm.common.security.smime.SMIMEHeader; import org.apache.log4j.PropertyConfigurator; import org.bouncycastle.cms.CMSException; import org.bouncycastle.mail.smime.SMIMEEnveloped; import org.bouncycastle.mail.smime.SMIMEEnvelopedParser; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class CMSEnvelopedInspectorImplTest { private static final Logger logger = LoggerFactory.getLogger(CMSEnvelopedInspectorImplTest.class); private static final File testDir = new File("test/resources/testdata/mail"); private static final File tempDir = new File("test/tmp"); private static SecurityFactory securityFactory; private static KeyStore keyStore; private static KeyStoreKeyProvider keyStoreKeyProvider; @BeforeClass public static void setUpBeforeClass() throws Exception { PropertyConfigurator.configure("conf/log4j.properties"); InitializeBouncycastle.initialize(); securityFactory = SecurityFactoryFactory.getSecurityFactory(); keyStore = loadKeyStore(new File("test/resources/testdata/keys/testCertificates.p12"), "test"); keyStoreKeyProvider = new KeyStoreKeyProvider(keyStore, "test"); } private static KeyStore loadKeyStore(File file, String password) throws KeyStoreException { try { KeyStore keyStore = securityFactory.createKeyStore("PKCS12"); // initialize key store keyStore.load(new FileInputStream(file), password.toCharArray()); return keyStore; } catch (NoSuchProviderException e) { throw new KeyStoreException(e); } catch (NoSuchAlgorithmException e) { throw new KeyStoreException(e); } catch (CertificateException e) { throw new KeyStoreException(e); } catch (FileNotFoundException e) { throw new KeyStoreException(e); } catch (IOException e) { throw new KeyStoreException(e); } } private static MimeMessage loadMessage(String filename) throws FileNotFoundException, MessagingException { File mail = new File(testDir, filename); MimeMessage message = MailUtils.loadMessage(mail); return message; } /* * Check for some headers which should exist because they were added to the signed or encrypted blob. */ private static void checkForEmbeddedHeaders(MimeMessage message) throws MessagingException { // the message should contain the signed from, to and subject assertEquals("<test@example.com>", message.getHeader("from", ",")); assertEquals("<test@example.com>", message.getHeader("to", ",")); assertEquals("normal message with attachment", message.getHeader("subject", ",")); } @Test public void testEnveloped() throws MessagingException, CMSException, CryptoMessageSyntaxException, IOException { MimeMessage message = loadMessage("encrypted-validcertificate.eml"); SMIMEEnveloped enveloped = new SMIMEEnveloped(message); CMSEnvelopedDataAdapter cmsEnveloped = CMSAdapterFactory.createAdapter(enveloped); assertTrue(cmsEnveloped instanceof CMSEnvelopedDataAdapterImpl); testEnveloped(cmsEnveloped); } @Test public void testEnvelopedParser() throws MessagingException, IOException, CMSException, CryptoMessageSyntaxException { MimeMessage message = loadMessage("encrypted-validcertificate.eml"); SMIMEEnvelopedParser envelopedParser = new SMIMEEnvelopedParser(message); CMSEnvelopedDataAdapter cmsEnveloped = CMSAdapterFactory.createAdapter(envelopedParser); assertTrue(cmsEnveloped instanceof CMSEnvelopedDataParserAdapterImpl); testEnveloped(cmsEnveloped); } public void testEnveloped(CMSEnvelopedDataAdapter cmsEnveloped) throws CryptoMessageSyntaxException, MessagingException, IOException { CMSEnvelopedInspector inspector = new CMSEnvelopedInspectorImpl(cmsEnveloped, keyStoreKeyProvider, securityFactory.getNonSensitiveProvider(), securityFactory.getSensitiveProvider()); List<RecipientInfo> recipients = inspector.getRecipients(); assertEquals(1, recipients.size()); RecipientInfo recipientInfo = recipients.get(0); logger.info( "Encryption Algorithm: " + SMIMEEncryptionAlgorithm.fromOID(inspector.getEncryptionAlgorithmOID())); logger.info(recipientInfo.toString()); KeyIdentifier recipientId = recipientInfo.getRecipientId(); assertTrue(recipientId instanceof KeyTransRecipientId); KeyTransRecipientId keyTransRecipientId = (KeyTransRecipientId) recipientId; assertEquals(new BigInteger("115FCD741088707366E9727452C9770", 16), keyTransRecipientId.getSerialNumber()); assertEquals(new X500Principal("EMAILADDRESS=ca@example.com, CN=MITM Test CA, L=Amsterdam, ST=NH, C=NL"), keyTransRecipientId.getIssuer()); byte[] decryptedContent = inspector.getContent(); MimeMessage decryptedMessage = MailUtils.byteArrayToMessage(decryptedContent); File file = new File(tempDir, "encrypted-validcertificate-decrypted.eml"); MailUtils.writeMessage(decryptedMessage, file); decryptedMessage = MailUtils.loadMessage(file); assertTrue(decryptedMessage.isMimeType("multipart/mixed")); assertEquals(SMIMEHeader.Type.NO_SMIME, SMIMEHeader.getSMIMEContentType(decryptedMessage)); checkForEmbeddedHeaders(decryptedMessage); } @Test public void testEnvelopedMultipleRecipients() throws MessagingException, CMSException, CryptoMessageSyntaxException, IOException { MimeMessage message = loadMessage("encrypt-15-recipients.eml"); SMIMEEnveloped enveloped = new SMIMEEnveloped(message); CMSEnvelopedDataAdapter cmsEnveloped = CMSAdapterFactory.createAdapter(enveloped); assertTrue(cmsEnveloped instanceof CMSEnvelopedDataAdapterImpl); testEnvelopedMultipleRecipients(cmsEnveloped); } @Test public void testEnvelopedMultipleRecipientsParser() throws MessagingException, CryptoMessageSyntaxException, IOException, CMSException { MimeMessage message = loadMessage("encrypt-15-recipients.eml"); SMIMEEnvelopedParser enveloped = new SMIMEEnvelopedParser(message); CMSEnvelopedDataAdapter cmsEnveloped = CMSAdapterFactory.createAdapter(enveloped); assertTrue(cmsEnveloped instanceof CMSEnvelopedDataParserAdapterImpl); testEnvelopedMultipleRecipients(cmsEnveloped); } public void testEnvelopedMultipleRecipients(CMSEnvelopedDataAdapter cmsEnveloped) throws CryptoMessageSyntaxException, MessagingException, IOException { CMSEnvelopedInspector inspector = new CMSEnvelopedInspectorImpl(cmsEnveloped, keyStoreKeyProvider, securityFactory.getNonSensitiveProvider(), securityFactory.getSensitiveProvider()); List<RecipientInfo> recipients = inspector.getRecipients(); assertEquals(15, recipients.size()); Set<String> serials = new HashSet<String>(); // check if the recipients are all different for (RecipientInfo recipientInfo : recipients) { String serial = ((KeyTransRecipientId) recipientInfo.getRecipientId()).getSerialNumber().toString(); serials.add(serial); } assertEquals(15, serials.size()); byte[] decryptedContent = inspector.getContent(); MimeMessage decryptedMessage = MailUtils.byteArrayToMessage(decryptedContent); File file = new File(tempDir, "testEnvelopedMultipleRecipients-decrypted.eml"); MailUtils.writeMessage(decryptedMessage, file); decryptedMessage = MailUtils.loadMessage(file); assertTrue(decryptedMessage.isMimeType("multipart/mixed")); assertEquals(SMIMEHeader.Type.NO_SMIME, SMIMEHeader.getSMIMEContentType(decryptedMessage)); checkForEmbeddedHeaders(decryptedMessage); } @Test(expected = RecipientInfoException.class) public void testDecryptIncorrectKey() throws Exception { MimeMessage message = loadMessage("encrypted-validcertificate.eml"); SMIMEEnveloped enveloped = new SMIMEEnveloped(message); CMSEnvelopedDataAdapter cmsEnveloped = CMSAdapterFactory.createAdapter(enveloped); assertTrue(cmsEnveloped instanceof CMSEnvelopedDataAdapterImpl); testDecryptIncorrectKey(cmsEnveloped); } @Test(expected = RecipientInfoException.class) public void testDecryptIncorrectKeyParser() throws Exception { MimeMessage message = loadMessage("encrypted-validcertificate.eml"); SMIMEEnvelopedParser envelopedParser = new SMIMEEnvelopedParser(message); CMSEnvelopedDataAdapter cmsEnveloped = new CMSEnvelopedDataParserAdapterImpl(envelopedParser); assertTrue(cmsEnveloped instanceof CMSEnvelopedDataParserAdapterImpl); testDecryptIncorrectKey(cmsEnveloped); } public void testDecryptIncorrectKey(CMSEnvelopedDataAdapter cmsEnveloped) throws Exception { CMSEnvelopedInspector inspector = new CMSEnvelopedInspectorImpl(cmsEnveloped, keyStoreKeyProvider, securityFactory.getNonSensitiveProvider(), securityFactory.getSensitiveProvider()); List<RecipientInfo> recipients = inspector.getRecipients(); assertEquals(1, recipients.size()); RecipientInfo info = recipients.get(0); PrivateKey key = (PrivateKey) keyStore.getKey("noEmail", "test".toCharArray()); // this should throw a RecipientInfoException because the key is incorrect info.getContent(key); } @Test public void testDecryptMulitpleTimes() throws Exception { MimeMessage message = loadMessage("encrypted-validcertificate.eml"); SMIMEEnveloped enveloped = new SMIMEEnveloped(message); CMSEnvelopedDataAdapter cmsEnveloped = CMSAdapterFactory.createAdapter(enveloped); assertTrue(cmsEnveloped instanceof CMSEnvelopedDataAdapterImpl); testDecryptMulitpleTimes(cmsEnveloped); } public void testDecryptMulitpleTimes(CMSEnvelopedDataAdapter cmsEnveloped) throws Exception { CMSEnvelopedInspector inspector = new CMSEnvelopedInspectorImpl(cmsEnveloped, keyStoreKeyProvider, securityFactory.getNonSensitiveProvider(), securityFactory.getSensitiveProvider()); List<RecipientInfo> recipients = inspector.getRecipients(); assertEquals(1, recipients.size()); RecipientInfo info = recipients.get(0); PrivateKey key = (PrivateKey) keyStore.getKey("Validcertificate", "test".toCharArray()); byte[] content1 = info.getContent(key); byte[] content2 = info.getContent(key); assertArrayEquals(content1, content2); } }