aboutsummaryrefslogtreecommitdiffstats
path: root/libraries/spongycastle/mail/src/test/java/org/spongycastle/mail/smime/test/SignedMailValidatorTest.java
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/spongycastle/mail/src/test/java/org/spongycastle/mail/smime/test/SignedMailValidatorTest.java')
-rw-r--r--libraries/spongycastle/mail/src/test/java/org/spongycastle/mail/smime/test/SignedMailValidatorTest.java474
1 files changed, 474 insertions, 0 deletions
diff --git a/libraries/spongycastle/mail/src/test/java/org/spongycastle/mail/smime/test/SignedMailValidatorTest.java b/libraries/spongycastle/mail/src/test/java/org/spongycastle/mail/smime/test/SignedMailValidatorTest.java
new file mode 100644
index 000000000..55ef89bd8
--- /dev/null
+++ b/libraries/spongycastle/mail/src/test/java/org/spongycastle/mail/smime/test/SignedMailValidatorTest.java
@@ -0,0 +1,474 @@
+package org.bouncycastle.mail.smime.test;
+
+import java.io.InputStream;
+import java.security.KeyPair;
+import java.security.Security;
+import java.security.cert.CertPath;
+import java.security.cert.CertStore;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CollectionCertStoreParameters;
+import java.security.cert.PKIXParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CRL;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TimeZone;
+
+import javax.mail.Address;
+import javax.mail.Message;
+import javax.mail.Session;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.x509.X509Extension;
+import org.bouncycastle.cert.jcajce.JcaCertStore;
+import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder;
+import org.bouncycastle.cms.test.CMSTestUtil;
+import org.bouncycastle.i18n.ErrorBundle;
+import org.bouncycastle.mail.smime.SMIMESignedGenerator;
+import org.bouncycastle.mail.smime.validator.SignedMailValidator;
+import org.bouncycastle.util.Store;
+import org.bouncycastle.x509.PKIXCertPathReviewer;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+
+public class SignedMailValidatorTest extends TestCase
+{
+ static String TEST_TRUST_ACHOR = "validator.root.crt";
+
+ public void testShortKey() throws Exception
+ {
+ String message = "validator.shortKey.eml";
+ PKIXParameters params = createDefaultParams();
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isValidSignature());
+ assertContainsMessage(result.getNotifications(),
+ "SignedMailValidator.shortSigningKey",
+ "Warning: The signing key is only 512 bits long.");
+ }
+
+ public void testKeyUsage() throws Exception
+ {
+ String message = "validator.keyUsage.eml";
+ PKIXParameters params = createDefaultParams();
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isVerifiedSignature());
+ assertTrue(result.getCertPathReview().isValidCertPath());
+ assertFalse(result.isValidSignature());
+
+ assertContainsMessage(
+ result.getErrors(),
+ "SignedMailValidator.signingNotPermitted",
+ "The key usage extension of signer certificate does not permit using the key for email signatures.");
+ }
+
+ public void testExtKeyUsage() throws Exception
+ {
+ String message = "validator.extKeyUsage.eml";
+ PKIXParameters params = createDefaultParams();
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isVerifiedSignature());
+ assertTrue(result.getCertPathReview().isValidCertPath());
+ assertFalse(result.isValidSignature());
+
+ assertContainsMessage(
+ result.getErrors(),
+ "SignedMailValidator.extKeyUsageNotPermitted",
+ "The extended key usage extension of the signer certificate does not permit using the key for email signatures.");
+ }
+
+ public void testNoEmail() throws Exception
+ {
+ String message = "validator.noEmail.eml";
+ PKIXParameters params = createDefaultParams();
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isVerifiedSignature());
+ assertTrue(result.getCertPathReview().isValidCertPath());
+ assertFalse(result.isValidSignature());
+
+ assertContainsMessage(
+ result.getErrors(),
+ "SignedMailValidator.noEmailInCert",
+ "The signer certificate is not usable for email signatures: it contains no email address.");
+ }
+
+ public void testNotYetValid() throws Exception
+ {
+ String message = "validator.notYetValid.eml";
+ PKIXParameters params = createDefaultParams();
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isVerifiedSignature());
+ assertFalse(result.isValidSignature());
+ assertContainsMessage(result.getErrors(),
+ "SignedMailValidator.certNotYetValid",
+ "The message was signed at Aug 28, 2006 3:04:01 PM GMT. But the certificate is not valid before Dec 28, 2006 2:19:31 PM GMT.");
+
+ PKIXCertPathReviewer review = result.getCertPathReview();
+ assertFalse(review.isValidCertPath());
+ assertContainsMessage(
+ review.getErrors(0),
+ "CertPathReviewer.certificateNotYetValid",
+ "Could not validate the certificate. Certificate is not valid until Dec 28, 2006 2:19:31 PM GMT.");
+ }
+
+ public void testExpired() throws Exception
+ {
+ String message = "validator.expired.eml";
+ PKIXParameters params = createDefaultParams();
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isVerifiedSignature());
+ assertFalse(result.isValidSignature());
+ assertContainsMessage(result.getErrors(),
+ "SignedMailValidator.certExpired",
+ "The message was signed at Sep 1, 2006 9:08:35 AM GMT. But the certificate expired at Sep 1, 2006 8:39:20 AM GMT.");
+
+ PKIXCertPathReviewer review = result.getCertPathReview();
+ assertFalse(review.isValidCertPath());
+ assertContainsMessage(
+ review.getErrors(0),
+ "CertPathReviewer.certificateExpired",
+ "Could not validate the certificate. Certificate expired on Sep 1, 2006 8:39:20 AM GMT.");
+ }
+
+ public void testRevoked() throws Exception
+ {
+ String message = "validator.revoked.eml";
+ PKIXParameters params = createDefaultParams();
+ List crlList = new ArrayList();
+ crlList.add(loadCRL("validator.revoked.crl"));
+ CertStore crls = CertStore.getInstance("Collection",new CollectionCertStoreParameters(crlList));
+ params.addCertStore(crls);
+ params.setRevocationEnabled(true);
+
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isVerifiedSignature());
+ assertFalse(result.isValidSignature());
+
+ PKIXCertPathReviewer review = result.getCertPathReview();
+ assertFalse(review.isValidCertPath());
+ assertContainsMessage(
+ review.getErrors(0),
+ "CertPathReviewer.certRevoked",
+ "The certificate was revoked at Sep 1, 2006 9:30:00 AM GMT. Reason: Key Compromise.");
+ }
+
+ public void testLongValidity() throws Exception
+ {
+ String message = "validator.longValidity.eml";
+ PKIXParameters params = createDefaultParams();
+
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isVerifiedSignature());
+ assertTrue(result.isValidSignature());
+
+ assertContainsMessage(result.getNotifications(),
+ "SignedMailValidator.longValidity",
+ "Warning: The signing certificate has a very long validity period: from Sep 1, 2006 11:00:00 AM GMT until Aug 8, 2106 11:00:00 AM GMT.");
+ }
+
+ public void testSelfSignedCert()
+ throws Exception
+ {
+ MimeBodyPart baseMsg = SMIMETestUtil.makeMimeBodyPart("Hello world!\n");
+ String signDN = "CN=Eric H. Echidna, E=eric@bouncycastle.org, O=Bouncy Castle, C=AU";
+ KeyPair signKP = CMSTestUtil.makeKeyPair();
+ X509Certificate signCert = CMSTestUtil.makeV1Certificate(signKP, signDN, signKP, signDN);
+
+ // check basic path validation
+ Set trustanchors = new HashSet();
+ TrustAnchor ta = new TrustAnchor(signCert, null);
+ trustanchors.add(ta);
+
+ X509Certificate rootCert = ta.getTrustedCert();
+
+ // init cert stores
+ List certStores = new ArrayList();
+ List certList = new ArrayList();
+ certList.add(rootCert);
+ CertStore store = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList));
+ certStores.add(store);
+
+ // first path
+ CertPath path = SignedMailValidator.createCertPath(rootCert, trustanchors, certStores);
+
+ assertTrue("path size is not 1", path.getCertificates().size() == 1);
+
+ // check message validation
+ certList = new ArrayList();
+
+ certList.add(signCert);
+
+ Store certs = new JcaCertStore(certList);
+
+ SMIMESignedGenerator gen = new SMIMESignedGenerator();
+
+ gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build("SHA1withRSA", signKP.getPrivate(), signCert));
+ gen.addCertificates(certs);
+
+ MimeMultipart signedMsg = gen.generate(baseMsg);
+
+ Properties props = System.getProperties();
+ Session session = Session.getDefaultInstance(props, null);
+
+ // read message
+ MimeMessage msg = new MimeMessage(session);
+
+ Address fromUser = new InternetAddress("\"Eric H. Echidna\"<eric@bouncycastle.org>");
+ Address toUser = new InternetAddress("example@bouncycastle.org");
+
+ msg.setFrom(fromUser);
+ msg.setRecipient(Message.RecipientType.TO, toUser);
+ msg.setContent(signedMsg, signedMsg.getContentType());
+
+ msg.saveChanges();
+
+ PKIXParameters params = new PKIXParameters(trustanchors);
+ params.setRevocationEnabled(false);
+
+ SignedMailValidator validator = new SignedMailValidator(msg, params);
+ SignerInformation signer = (SignerInformation) validator
+ .getSignerInformationStore().getSigners().iterator().next();
+
+ SignedMailValidator.ValidationResult res = validator.getValidationResult(signer);
+
+ assertTrue(res.isVerifiedSignature());
+ assertTrue(res.isValidSignature());
+ }
+
+// TODO: this test needs to be replaced, unfortunately it was working due to a bug in
+// trust anchor extension handling
+// public void testCorruptRootStore() throws Exception
+// {
+// String message = "validator.validMail.eml";
+// Set trustanchors = new HashSet();
+// trustanchors.add(getTrustAnchor(TEST_TRUST_ACHOR));
+// trustanchors.add(getTrustAnchor("validator.fakeRoot.crt"));
+// PKIXParameters params = new PKIXParameters(trustanchors);
+// params.setRevocationEnabled(false);
+//
+// SignedMailValidator.ValidationResult result = doTest(message, params);
+//
+// assertTrue(result.isVerifiedSignature());
+// assertFalse(result.isValidSignature());
+//
+// PKIXCertPathReviewer review = result.getCertPathReview();
+//
+// assertFalse(review.isValidCertPath());
+// assertContainsMessage(review.getErrors(-1),
+// "CertPathReviewer.conflictingTrustAnchors",
+// "Warning: corrupt trust root store: There are 2 trusted public keys for the CA \"CN=SignedMailValidatorTest Root, C=CH\" - please ensure with CA which is the correct key.");
+// }
+
+ public void testCircular() throws Exception
+ {
+ String message = "circular.eml";
+ PKIXParameters params = createDefaultParams();
+ SignedMailValidator.ValidationResult result = doTest(message, params);
+
+ assertTrue(result.isVerifiedSignature());
+ assertFalse(result.isValidSignature());
+ assertFalse(result.getCertPathReview().isValidCertPath());
+ assertTrue("cert path size", result.getCertPathReview().getCertPathSize() > 2);
+ }
+
+ public void testExtendedReviewer() throws Exception
+ {
+ try
+ {
+ // Get a Session object with the default properties.
+ Properties props = System.getProperties();
+ Session session = Session.getDefaultInstance(props, null);
+
+ // read message
+ MimeMessage msg = new MimeMessage(session, getClass().getResourceAsStream("validator.shortKey.eml"));
+
+ SignedMailValidator validator = new SignedMailValidator(msg, createDefaultParams(), String.class);
+ fail();
+ }
+ catch (IllegalArgumentException e)
+ {
+ assertTrue(e.getMessage().startsWith("certPathReviewerClass is not a subclass of"));
+ }
+
+ // Get a Session object with the default properties.
+ Properties props = System.getProperties();
+ Session session = Session.getDefaultInstance(props, null);
+
+ // read message
+ MimeMessage msg = new MimeMessage(session, getClass().getResourceAsStream("validator.shortKey.eml"));
+
+ SignedMailValidator validator = new SignedMailValidator(msg, createDefaultParams(), DummyCertPathReviewer.class);
+ SignerInformation sInfo = (SignerInformation) validator.getSignerInformationStore().getSigners().iterator().next();
+ SignedMailValidator.ValidationResult result = validator.getValidationResult(sInfo);
+
+ assertTrue(result.isValidSignature());
+ assertContainsMessage(result.getNotifications(),
+ "SignedMailValidator.shortSigningKey",
+ "Warning: The signing key is only 512 bits long.");
+ }
+
+ public void testCreateCertPath() throws Exception
+ {
+ // load trust anchor
+ Set trustanchors = new HashSet();
+ TrustAnchor ta = getTrustAnchor("certpath_root.crt");
+ trustanchors.add(ta);
+
+ X509Certificate rootCert = ta.getTrustedCert();
+ X509Certificate interCert1 = loadCert("certpath_inter1.crt");
+ X509Certificate interCert2 = loadCert("certpath_inter2.crt");
+ X509Certificate endCert1 = loadCert("certpath_end1.crt");
+ X509Certificate endCert2 = loadCert("certpath_end2.crt");
+
+ // init cert stores
+ List certStores = new ArrayList();
+ List certList = new ArrayList();
+ certList.add(interCert1);
+ certList.add(interCert2);
+ CertStore store = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certList));
+ certStores.add(store);
+
+ // first path
+ CertPath path = SignedMailValidator.createCertPath(endCert1, trustanchors, certStores);
+ assertTrue("path size is not 3", path.getCertificates().size() == 3);
+ assertEquals("different end certificate", path.getCertificates().get(0), endCert1);
+ assertEquals("different intermediate certificate", path.getCertificates().get(1), interCert1);
+ assertEquals("different root certificate", path.getCertificates().get(2), rootCert);
+
+ // second path
+ path = SignedMailValidator.createCertPath(endCert2, trustanchors, certStores);
+ assertTrue("path size is not 3", path.getCertificates().size() == 3);
+ assertEquals("different end certificate", path.getCertificates().get(0), endCert2);
+ assertEquals("different intermediate certificate", path.getCertificates().get(1), interCert2);
+ assertEquals("different root certificate", path.getCertificates().get(2), rootCert);
+ }
+
+ private SignedMailValidator.ValidationResult doTest(String message,
+ PKIXParameters params) throws Exception
+ {
+ // Get a Session object with the default properties.
+ Properties props = System.getProperties();
+ Session session = Session.getDefaultInstance(props, null);
+
+ // read message
+ MimeMessage msg = new MimeMessage(session, getClass().getResourceAsStream(message));
+
+ SignedMailValidator validator = new SignedMailValidator(msg, params);
+ SignerInformation signer = (SignerInformation) validator
+ .getSignerInformationStore().getSigners().iterator().next();
+ return validator.getValidationResult(signer);
+ }
+
+ private void assertContainsMessage(List msgList, String messageId,
+ String text) throws Exception
+ {
+ Iterator it = msgList.iterator();
+ boolean found = false;
+ while (it.hasNext())
+ {
+ ErrorBundle message = (ErrorBundle) it.next();
+ if (message.getId().equals(messageId))
+ {
+ found = true;
+ assertEquals(text, message.getText(Locale.ENGLISH, TimeZone
+ .getTimeZone("GMT")));
+ break;
+ }
+ }
+ assertTrue("Expected message not found!", found);
+ }
+
+ private PKIXParameters createDefaultParams() throws Exception
+ {
+ Set trustanchors = new HashSet();
+ trustanchors.add(getTrustAnchor(TEST_TRUST_ACHOR));
+ PKIXParameters defParams = new PKIXParameters(trustanchors);
+ defParams.setRevocationEnabled(false);
+
+ return defParams;
+ }
+
+ private TrustAnchor getTrustAnchor(String trustcert) throws Exception
+ {
+ X509Certificate cert = loadCert(trustcert);
+ if (cert != null)
+ {
+ byte[] ncBytes = cert
+ .getExtensionValue(X509Extension.nameConstraints.getId());
+
+ if (ncBytes != null)
+ {
+ ASN1Encodable extValue = X509ExtensionUtil
+ .fromExtensionValue(ncBytes);
+ return new TrustAnchor(cert, extValue.toASN1Primitive().getEncoded(ASN1Encoding.DER));
+ }
+ return new TrustAnchor(cert, null);
+ }
+ return null;
+ }
+
+ private X509Certificate loadCert(String certfile) throws Exception
+ {
+ X509Certificate cert = null;
+ InputStream in = getClass().getResourceAsStream(certfile);
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
+ cert = (X509Certificate) cf.generateCertificate(in);
+ return cert;
+ }
+
+ private X509CRL loadCRL(String crlfile) throws Exception
+ {
+ X509CRL crl = null;
+ InputStream in = this.getClass().getResourceAsStream(crlfile);
+
+ CertificateFactory cf = CertificateFactory.getInstance("x.509", "BC");
+ crl = (X509CRL) cf.generateCRL(in);
+ return crl;
+ }
+
+ public void setUp()
+ {
+ if (Security.getProvider("BC") == null)
+ {
+ Security
+ .addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
+ }
+ }
+
+ public static void main(String[] args) throws Exception
+ {
+ junit.textui.TestRunner.run(suite());
+ }
+
+ public static Test suite() throws Exception
+ {
+ TestSuite suite = new TestSuite("SignedMailValidator Tests");
+
+ suite.addTestSuite(SignedMailValidatorTest.class);
+
+ return suite;
+ }
+
+}