You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ba...@apache.org on 2010/06/09 00:07:02 UTC

svn commit: r952843 - in /james/jdkim/trunk: mailets/src/test/java/org/apache/james/jdkim/mailets/ main/src/main/java/org/apache/james/jdkim/ main/src/main/java/org/apache/james/jdkim/api/ main/src/main/java/org/apache/james/jdkim/tagvalue/

Author: bago
Date: Tue Jun  8 22:07:01 2010
New Revision: 952843

URL: http://svn.apache.org/viewvc?rev=952843&view=rev
Log:
Added basic support for t= parameter (signature timestamp) in the signature record (JDKIM-15)

Modified:
    james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java
    james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java
    james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/api/SignatureRecord.java
    james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java

Modified: james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java?rev=952843&r1=952842&r2=952843&view=diff
==============================================================================
--- james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java (original)
+++ james/jdkim/trunk/mailets/src/test/java/org/apache/james/jdkim/mailets/DKIMSignTest.java Tue Jun  8 22:07:01 2010
@@ -22,6 +22,7 @@ package org.apache.james.jdkim.mailets;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.util.List;
 import java.util.Properties;
 
 import javax.mail.Address;
@@ -35,6 +36,7 @@ import junit.framework.TestCase;
 
 import org.apache.james.jdkim.DKIMVerifier;
 import org.apache.james.jdkim.MockPublicKeyRecordRetriever;
+import org.apache.james.jdkim.api.SignatureRecord;
 import org.apache.james.jdkim.exceptions.FailException;
 import org.apache.james.jdkim.exceptions.PermFailException;
 import org.apache.mailet.Mail;
@@ -64,7 +66,7 @@ public class DKIMSignTest extends TestCa
 
     public void testDKIMSign() throws MessagingException, IOException,
             FailException {
-        String message = "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bo...@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\n";
+        String message = "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bo...@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova\r\n";
 
         Mailet mailet = new DKIMSign();
 
@@ -74,10 +76,45 @@ public class DKIMSignTest extends TestCa
                 .setProperty(
                         "signatureTemplate",
                         "v=1; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;");
+        mci.setProperty("privateKey", TESTING_PEM);
+
+        mailet.init(mci);
+
+        Mail mail = new FakeMail();
+        mail.setMessage(new MimeMessage(Session
+                .getDefaultInstance(new Properties()),
+                new ByteArrayInputStream(message.getBytes())));
+
+        mailet.service(mail);
+
+        Mailet m7bit = new ConvertTo7Bit();
+        m7bit.init(mci);
+        m7bit.service(mail);
+
+        ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
+        mail.getMessage().writeTo(rawMessage);
+        String res = rawMessage.toString();
+
+        MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
+                "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
+                "selector", "example.com");
+        new DKIMVerifier(mockPublicKeyRecordRetriever)
+                .verify(new ByteArrayInputStream(res.getBytes()));
+    }
+
+    public void testDKIMSignFuture() throws MessagingException, IOException,
+            FailException {
+        String message = "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bo...@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova\r\n";
+
+        Mailet mailet = new DKIMSign();
+
+        FakeMailetConfig mci = new FakeMailetConfig("Test",
+                new FakeMailContext());
         mci
                 .setProperty(
-                        "privateKey",
-                        TESTING_PEM);
+                        "signatureTemplate",
+                        "v=1; t="+((System.currentTimeMillis()/1000)+1000)+"; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;");
+        mci.setProperty("privateKey", TESTING_PEM);
 
         mailet.init(mci);
 
@@ -96,11 +133,62 @@ public class DKIMSignTest extends TestCa
         mail.getMessage().writeTo(rawMessage);
         String res = rawMessage.toString();
 
-        MockPublicKeyRecordRetriever MockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
+        MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
                 "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
                 "selector", "example.com");
-        new DKIMVerifier(MockPublicKeyRecordRetriever)
+        try {
+            new DKIMVerifier(mockPublicKeyRecordRetriever)
+                    .verify(new ByteArrayInputStream(res.getBytes()));
+            fail("Expecting signature to be ignored");
+        } catch (PermFailException e) {
+            // signature ignored, so fail for missing signatures.
+        }
+    }
+
+
+    public void testDKIMSignTime() throws MessagingException, IOException,
+            FailException {
+        String message = "Received: by 10.XX.XX.12 with SMTP id dfgskldjfhgkljsdfhgkljdhfg;\r\n\tTue, 06 Oct 2009 07:37:34 -0700 (PDT)\r\nReturn-Path: <bo...@example.com>\r\nReceived: from example.co.uk (example.co.uk [XX.XXX.125.19])\r\n\tby mx.example.com with ESMTP id dgdfgsdfgsd.97.2009.10.06.07.37.32;\r\n\tTue, 06 Oct 2009 07:37:32 -0700 (PDT)\r\nFrom: apache@bago.org\r\nTo: apache@bago.org\r\n\r\nbody\r\nprova\r\n";
+
+        Mailet mailet = new DKIMSign();
+
+        FakeMailetConfig mci = new FakeMailetConfig("Test",
+                new FakeMailContext());
+        mci
+                .setProperty(
+                        "signatureTemplate",
+                        "v=1; t=; s=selector; d=example.com; h=from:to:received:received; a=rsa-sha256; bh=; b=;");
+        mci.setProperty("privateKey", TESTING_PEM);
+
+        mailet.init(mci);
+
+        Mail mail = new FakeMail();
+        mail.setMessage(new MimeMessage(Session
+                .getDefaultInstance(new Properties()),
+                new ByteArrayInputStream(message.getBytes())));
+
+        mailet.service(mail);
+
+        Mailet m7bit = new ConvertTo7Bit();
+        m7bit.init(mci);
+        m7bit.service(mail);
+
+        ByteArrayOutputStream rawMessage = new ByteArrayOutputStream();
+        mail.getMessage().writeTo(rawMessage);
+        String res = rawMessage.toString();
+
+        MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
+                "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
+                "selector", "example.com");
+        List/* SignatureRecord */ rs = new DKIMVerifier(mockPublicKeyRecordRetriever)
                 .verify(new ByteArrayInputStream(res.getBytes()));
+        
+        // check we have a valued signatureTimestamp
+        assertNotNull(((SignatureRecord) rs.get(0)).getSignatureTimestamp());
+        long ref = System.currentTimeMillis() / 1000;
+        // Chech that the signature timestamp is in the past 60 seconds.
+        assertTrue(((SignatureRecord) rs.get(0)).getSignatureTimestamp().longValue() <= ref);
+        assertTrue(((SignatureRecord) rs.get(0)).getSignatureTimestamp().longValue() >= ref - 60);
     }
 
     public void testDKIMSignMessageAsText() throws MessagingException,
@@ -109,7 +197,7 @@ public class DKIMSignTest extends TestCa
                 .getDefaultInstance(new Properties()));
         mm.addFrom(new Address[] { new InternetAddress("io@bago.org") });
         mm.addRecipient(RecipientType.TO, new InternetAddress("io@bago.org"));
-        mm.setText("An 8bit encoded body with €uro symbol.", "ISO-8859-15");
+        mm.setText("An 8bit encoded body with \u20ACuro symbol.", "ISO-8859-15");
 
         Mailet mailet = new DKIMSign();
 
@@ -140,10 +228,10 @@ public class DKIMSignTest extends TestCa
         mail.getMessage().writeTo(rawMessage);
         String res = rawMessage.toString();
 
-        MockPublicKeyRecordRetriever MockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
+        MockPublicKeyRecordRetriever mockPublicKeyRecordRetriever = new MockPublicKeyRecordRetriever(
                 "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDYDaYKXzwVYwqWbLhmuJ66aTAN8wmDR+rfHE8HfnkSOax0oIoTM5zquZrTLo30870YMfYzxwfB6j/Nz3QdwrUD/t0YMYJiUKyWJnCKfZXHJBJ+yfRHr7oW+UW3cVo9CG2bBfIxsInwYe175g9UjyntJpWueqdEIo1c2bhv9Mp66QIDAQAB;",
                 "selector", "example.com");
-        new DKIMVerifier(MockPublicKeyRecordRetriever)
+        new DKIMVerifier(mockPublicKeyRecordRetriever)
                 .verify(new ByteArrayInputStream(res.getBytes()));
     }
 

Modified: james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java?rev=952843&r1=952842&r2=952843&view=diff
==============================================================================
--- james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java (original)
+++ james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMVerifier.java Tue Jun  8 22:07:01 2010
@@ -266,6 +266,17 @@ public class DKIMVerifier extends DKIMCo
                         throw new PermFailException(e.getMessage());
                     }
 
+                    // Specification say we MAY refuse to verify the signature.
+                    if (signatureRecord.getSignatureTimestamp() != null) {
+                        long signedTime = signatureRecord.getSignatureTimestamp().longValue();
+                        long elapsed = (System.currentTimeMillis()/1000 - signedTime);
+                        if (elapsed < 0) {
+                            // throw new IllegalStateException("Signature date is "
+                            //        + getTimeMeasure(elapsed) + " in the future.");
+                            break;
+                        }
+                    }
+
                     // TODO here we could check more parameters for
                     // validation before running a network operation like the
                     // dns lookup.

Modified: james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/api/SignatureRecord.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/api/SignatureRecord.java?rev=952843&r1=952842&r2=952843&view=diff
==============================================================================
--- james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/api/SignatureRecord.java (original)
+++ james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/api/SignatureRecord.java Tue Jun  8 22:07:01 2010
@@ -67,4 +67,6 @@ public interface SignatureRecord {
     
     public abstract String toUnsignedString();
 
+    public abstract Long getSignatureTimestamp();
+
 }
\ No newline at end of file

Modified: james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java
URL: http://svn.apache.org/viewvc/james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java?rev=952843&r1=952842&r2=952843&view=diff
==============================================================================
--- james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java (original)
+++ james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java Tue Jun  8 22:07:01 2010
@@ -74,32 +74,10 @@ public class SignatureRecordImpl extends
         // (signature expired)
         if (getValue("x") != null) {
             long expiration = Long.parseLong(getValue("x").toString());
-            long lifetime = (expiration - System.currentTimeMillis() / 1000);
-            String measure = "s";
+            long lifetime = (expiration - System.currentTimeMillis()/1000);
             if (lifetime < 0) {
-                lifetime = -lifetime;
-                if (lifetime > 600) {
-                    lifetime = lifetime / 60;
-                    measure = "m";
-                    if (lifetime > 600) {
-                        lifetime = lifetime / 60;
-                        measure = "h";
-                        if (lifetime > 120) {
-                            lifetime = lifetime / 24;
-                            measure = "d";
-                            if (lifetime > 90) {
-                                lifetime = lifetime / 30;
-                                measure = " months";
-                                if (lifetime > 24) {
-                                    lifetime = lifetime / 12;
-                                    measure = " years";
-                                }
-                            }
-                        }
-                    }
-                }
                 throw new IllegalStateException("Signature is expired since "
-                        + lifetime + measure + ".");
+                        + getTimeMeasure(lifetime) + ".");
             }
         }
 
@@ -111,6 +89,33 @@ public class SignatureRecordImpl extends
         // this class).
     }
 
+    private String getTimeMeasure(long lifetime) {
+        String measure = "s";
+        lifetime = -lifetime;
+        if (lifetime > 600) {
+            lifetime = lifetime / 60;
+            measure = "m";
+            if (lifetime > 600) {
+                lifetime = lifetime / 60;
+                measure = "h";
+                if (lifetime > 120) {
+                    lifetime = lifetime / 24;
+                    measure = "d";
+                    if (lifetime > 90) {
+                        lifetime = lifetime / 30;
+                        measure = " months";
+                        if (lifetime > 24) {
+                            lifetime = lifetime / 12;
+                            measure = " years";
+                        }
+                    }
+                }
+            }
+        }
+        String lifetimeMeasure = lifetime + measure;
+        return lifetimeMeasure;
+    }
+
     /**
      * @see org.apache.james.jdkim.api.SignatureRecord#getHeaders()
      */
@@ -274,6 +279,12 @@ public class SignatureRecordImpl extends
             return Integer.parseInt(limit);
     }
 
+    public Long getSignatureTimestamp() {
+        CharSequence cs = getValue("t");
+        if (cs == null) return null;
+        return Long.valueOf(Long.parseLong(cs.toString()));
+    }
+
     public String getBodyCanonicalisationMethod() {
         String c = getValue("c").toString();
         int pSlash = c.toString().indexOf("/");
@@ -315,11 +326,14 @@ public class SignatureRecordImpl extends
     public void setBodyHash(byte[] newBodyHash) {
         String bodyHash = new String(Base64.encodeBase64(newBodyHash));
         setValue("bh", bodyHash);
+        // If a t=; parameter is present in the signature, make sure to 
+        // fill it with the current timestamp
+        if (getValue("t") != null && getValue("t").toString().trim().length() == 0) {
+            setValue("t", ""+(System.currentTimeMillis() / 1000));
+        }
     }
 
     public String toUnsignedString() {
         return toString().replaceFirst("b=[^;]*", "b=");
     }
-
-
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org