Author: bago
Date: Sun Oct 11 20:04:57 2009
New Revision: 824132

URL: http://svn.apache.org/viewvc?rev=824132&view=rev
Log:
Refactored SignatureRecord and its Impl to better support signing/verification.
It now supports toString representation and "unsigned" representation.

Modified:
    
james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java
    james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMCommon.java
    james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMSigner.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/PublicKeyRecordImpl.java
    
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/SignatureRecordImpl.java
    
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java

Modified: 
james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java
URL: 
http://svn.apache.org/viewvc/james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java?rev=824132&r1=824131&r2=824132&view=diff
==============================================================================
--- 
james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java
 (original)
+++ 
james/jdkim/trunk/mailets/src/main/java/org/apache/james/jdkim/mailets/DKIMSign.java
 Sun Oct 11 20:04:57 2009
@@ -120,7 +120,7 @@
     public void service(Mail mail) throws MessagingException {
         DKIMSigner signer = new DKIMSigner(signatureTemplate, privateKey);
         SignatureRecord signRecord = signer
-                .newSignatureRecord(signatureTemplate);
+                .newSignatureRecordTemplate(signatureTemplate);
         try {
             BodyHasher bhj = signer.newBodyHasher(signRecord);
             MimeMessage message = mail.getMessage();

Modified: 
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMCommon.java
URL: 
http://svn.apache.org/viewvc/james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMCommon.java?rev=824132&r1=824131&r2=824132&view=diff
==============================================================================
--- james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMCommon.java 
(original)
+++ james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMCommon.java 
Sun Oct 11 20:04:57 2009
@@ -60,7 +60,7 @@
     }
 
     protected static void signatureCheck(Headers h, SignatureRecord sign,
-            List headers, String signatureStub, Signature signature)
+            List headers, Signature signature)
             throws SignatureException, PermFailException {
 
         boolean relaxedHeaders = SignatureRecord.RELAXED.equals(sign
@@ -97,6 +97,7 @@
             }
         }
 
+        String signatureStub = "DKIM-Signature:" + sign.toUnsignedString();
         updateSignature(signature, relaxedHeaders, "dkim-signature",
                 signatureStub);
     }

Modified: 
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMSigner.java
URL: 
http://svn.apache.org/viewvc/james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMSigner.java?rev=824132&r1=824131&r2=824132&view=diff
==============================================================================
--- james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMSigner.java 
(original)
+++ james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/DKIMSigner.java 
Sun Oct 11 20:04:57 2009
@@ -52,7 +52,7 @@
         this.signatureRecordTemplate = signatureRecordTemplate;
     }
 
-    public SignatureRecord newSignatureRecord(String record) {
+    public SignatureRecord newSignatureRecordTemplate(String record) {
         return new SignatureRecordImpl(record);
     }
 
@@ -70,7 +70,7 @@
                 throw new PermFailException("MIME parsing exception: "
                         + e1.getMessage(), e1);
             }
-            SignatureRecord srt = newSignatureRecord(signatureRecordTemplate);
+            SignatureRecord srt = 
newSignatureRecordTemplate(signatureRecordTemplate);
             try {
                 BodyHasher bhj = newBodyHasher(srt);
 
@@ -92,10 +92,9 @@
     public String sign(Headers message, BodyHasher bhj)
             throws PermFailException {
         byte[] computedHash = bhj.getDigest();
-        String newField = "DKIM-Signature: "
-                + signatureRecordTemplate.replaceAll("bh=[^;]*", "bh="
-                        + new String(Base64.encodeBase64(computedHash)));
-
+        
+        bhj.getSignatureRecord().setBodyHash(computedHash);
+        
         List headers = bhj.getSignatureRecord().getHeaders();
         try {
             // TODO handle b= in SignatureRecord.
@@ -105,11 +104,12 @@
             // with the right test representation.
             // we need a method to "regenerate the text representation" and to
             // retrieve it when it is valid.
-            byte[] signatureHash = signatureSign(message, newField, bhj
+            byte[] signatureHash = signatureSign(message, bhj
                     .getSignatureRecord(), privateKey, headers);
-            newField = newField.replaceAll("b=[^;]*", "b="
-                    + new String(Base64.encodeBase64(signatureHash)));
-            return newField;
+
+            bhj.getSignatureRecord().setSignature(signatureHash);
+
+            return "DKIM-Signature:"+bhj.getSignatureRecord().toString();
         } catch (InvalidKeyException e) {
             throw new PermFailException("Invalid key: " + e.getMessage(), e);
         } catch (NoSuchAlgorithmException e) {
@@ -121,8 +121,7 @@
         }
     }
 
-    private byte[] signatureSign(Headers h, String signatureStub,
-            SignatureRecord sign, PrivateKey key, List headers)
+    private byte[] signatureSign(Headers h, SignatureRecord sign, PrivateKey 
key, List headers)
             throws NoSuchAlgorithmException, InvalidKeyException,
             SignatureException, PermFailException {
 
@@ -130,7 +129,8 @@
                 .toString().toUpperCase()
                 + "with" + sign.getHashKeyType().toString().toUpperCase());
         signature.initSign(key);
-        signatureCheck(h, sign, headers, signatureStub, signature);
+
+        signatureCheck(h, sign, headers, signature);
         return signature.sign();
     }
 

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=824132&r1=824131&r2=824132&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 
Sun Oct 11 20:04:57 2009
@@ -247,7 +247,8 @@
             try {
                 int pos = signatureField.indexOf(':');
                 if (pos > 0) {
-                    String v = signatureField.substring(pos + 1, 
signatureField.length());
+                    String v = signatureField.substring(pos + 1, signatureField
+                            .length());
                     SignatureRecord signatureRecord;
                     try {
                         signatureRecord = newSignatureRecord(v);
@@ -265,7 +266,9 @@
 
                     List signedHeadersList = signatureRecord.getHeaders();
 
-                    signatureVerify(messageHeaders, signatureField, 
signatureRecord, publicKeyRecord, signedHeadersList);
+                    byte[] decoded = signatureRecord.getSignature();
+                    signatureVerify(messageHeaders, signatureRecord, decoded,
+                            publicKeyRecord, signedHeadersList);
 
                     // we track all canonicalizations+limit+bodyHash we
                     // see so to be able to check all of them in a single
@@ -299,7 +302,8 @@
         if (bodyHashJobs.size() == 0) {
             throw prepareException(signatureExceptions);
         } else if (bodyHashJobs.size() == 1) {
-            o = ((BodyHasher) 
bodyHashJobs.values().iterator().next()).getOutputStream();
+            o = ((BodyHasher) bodyHashJobs.values().iterator().next())
+                    .getOutputStream();
         } else {
             o = new CompoundOutputStream(outputStreams);
         }
@@ -308,9 +312,8 @@
         DKIMCommon.streamCopy(bodyInputStream, o);
 
         List/* SignatureRecord */verifiedSignatures = new LinkedList();
-        for (Iterator i = bodyHashJobs.keySet().iterator(); i.hasNext();) {
-            String fval = (String) i.next();
-            BodyHasher bhj = (BodyHasher) bodyHashJobs.get(fval);
+        for (Iterator i = bodyHashJobs.values().iterator(); i.hasNext();) {
+            BodyHasher bhj = (BodyHasher) i.next();
 
             byte[] computedHash = bhj.getDigest();
             byte[] expectedBodyHash = bhj.getSignatureRecord().getBodyHash();
@@ -318,7 +321,7 @@
             if (!Arrays.equals(expectedBodyHash, computedHash)) {
                 signatureExceptions
                         .put(
-                                fval,
+                                
"DKIM-Signature:"+bhj.getSignatureRecord().toString(),
                                 new PermFailException(
                                         "Computed bodyhash is different from 
the expected one"));
             } else {
@@ -354,29 +357,25 @@
             // TODO loops signatureExceptions to give a more complete
             // response, using nested exception or a compound exception.
             // System.out.println(signatureExceptions);
-            return new PermFailException("found "
-                    + signatureExceptions.size() + " invalid signatures");
+            return new PermFailException("found " + signatureExceptions.size()
+                    + " invalid signatures");
         }
     }
 
-    private void signatureVerify(Headers h, String dkimSignature,
-            SignatureRecord sign, PublicKeyRecord key, List headers)
+    private void signatureVerify(Headers h, SignatureRecord sign,
+            byte[] decoded, PublicKeyRecord key, List headers)
             throws NoSuchAlgorithmException, InvalidKeyException,
             SignatureException, PermFailException {
-        byte[] decoded = sign.getSignature();
-
-        String signatureStub = dkimSignature.replaceAll("b=[^;]*", "b=");
 
         Signature signature = Signature.getInstance(sign.getHashMethod()
                 .toString().toUpperCase()
                 + "with" + sign.getHashKeyType().toString().toUpperCase());
         signature.initVerify(key.getPublicKey());
 
-        signatureCheck(h, sign, headers, signatureStub, signature);
+        signatureCheck(h, sign, headers, signature);
 
         if (!signature.verify(decoded))
-            throw new PermFailException(
-                    "Header signature does not verify");
+            throw new PermFailException("Header signature does not verify");
     }
 
 }

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=824132&r1=824131&r2=824132&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
 Sun Oct 11 20:04:57 2009
@@ -21,15 +21,16 @@
 
 import java.util.List;
 
+
+/**
+ * A complete SignatureRecord, including the signature and "formatted".
+ */
 public interface SignatureRecord {
 
     public final static String RELAXED = "relaxed";
     public final static String SIMPLE = "simple";
-
     public final static String ALL = ";all;";
 
-    public abstract void validate();
-
     public abstract List/* CharSequence */getHeaders();
 
     public abstract CharSequence getIdentityLocalPart();
@@ -50,12 +51,20 @@
 
     public abstract int getBodyHashLimit();
 
-    public abstract byte[] getSignature();
-
     public abstract String getHeaderCanonicalisationMethod();
 
     public abstract String getBodyCanonicalisationMethod();
 
     public abstract List getRecordLookupMethods();
 
+    public abstract void validate();
+
+    public abstract byte[] getSignature();
+    
+    public abstract void setSignature(byte[] newSignature);
+    
+    public abstract void setBodyHash(byte[] newBodyHash);
+    
+    public abstract String toUnsignedString();
+
 }
\ No newline at end of file

Modified: 
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java
URL: 
http://svn.apache.org/viewvc/james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java?rev=824132&r1=824131&r2=824132&view=diff
==============================================================================
--- 
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java
 (original)
+++ 
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/PublicKeyRecordImpl.java
 Sun Oct 11 20:04:57 2009
@@ -28,6 +28,7 @@
 import java.util.ArrayList;
 import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
 
 import org.apache.commons.codec.binary.Base64;
@@ -50,10 +51,13 @@
         super(data);
     }
 
-    protected void init() {
+    protected Map newTagValue() {
         // extensions may override this to use TreeMaps in order to keep track
         // of orders
-        tagValues = new LinkedHashMap();
+        return new LinkedHashMap();
+    }
+
+    protected void init() {
         mandatoryTags.add("p");
         defaults.put("v", "DKIM1");
         defaults.put("g", "*");
@@ -68,10 +72,9 @@
     // in the same way?
     public void validate() {
         super.validate();
-        if (tagValues.containsKey("v")) {
+        if (containsTag("v")) {
             // if "v" is specified it must be the first tag
-            String firstKey = (String) ((LinkedHashMap) tagValues).keySet()
-                    .iterator().next();
+            String firstKey = (String) tagSet().iterator().next();
             if (!"v".equals(firstKey))
                 throw new IllegalStateException(
                         "Existing v= tag MUST be the first in the record list 
("

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=824132&r1=824131&r2=824132&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
 Sun Oct 11 20:04:57 2009
@@ -38,8 +38,6 @@
     }
 
     protected void init() {
-        super.init();
-
         mandatoryTags.add("v");
         mandatoryTags.add("a");
         mandatoryTags.add("b");
@@ -48,7 +46,7 @@
         mandatoryTags.add("h");
         mandatoryTags.add("s");
 
-        defaults.put("c", "simple/simple");
+        defaults.put("c", SIMPLE+"/"+SIMPLE);
         defaults.put("l", ALL);
         defaults.put("q", "dns/txt");
     }
@@ -282,7 +280,7 @@
         if (pSlash != -1) {
             return c.substring(pSlash + 1);
         } else {
-            return "simple";
+            return SIMPLE;
         }
     }
 
@@ -309,4 +307,19 @@
         return res;
     }
 
+    public void setSignature(byte[] newSignature) {
+        String signature = new String(Base64.encodeBase64(newSignature));
+        setValue("b", signature);
+    }
+
+    public void setBodyHash(byte[] newBodyHash) {
+        String bodyHash = new String(Base64.encodeBase64(newBodyHash));
+        setValue("bh", bodyHash);
+    }
+
+    public String toUnsignedString() {
+        return toString().replaceFirst("b=[^;]*", "b=");
+    }
+
+
 }

Modified: 
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java
URL: 
http://svn.apache.org/viewvc/james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java?rev=824132&r1=824131&r2=824132&view=diff
==============================================================================
--- 
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java
 (original)
+++ 
james/jdkim/trunk/main/src/main/java/org/apache/james/jdkim/tagvalue/TagValue.java
 Sun Oct 11 20:04:57 2009
@@ -45,11 +45,19 @@
             + "((\r\n[\t ]|[\t ])+" + tval + ")*)?$");
 
     // we may use a TreeMap because we may need to know original order.
-    protected Map/* String, CharSequence */tagValues;
+    private Map/* String, CharSequence */tagValues;
 
     protected Set/* String */mandatoryTags = new HashSet();
     protected Map/* String, CharSequence */defaults = new HashMap();
+    private String stringRepresentation = null;
 
+    protected Set tagSet() {
+        return tagValues.keySet();
+    }
+    protected boolean containsTag(String tag) {
+        return tagValues.containsKey(tag);
+    }
+    
     protected CharSequence trimFWS(CharSequence data, int tStart, int tStop,
             boolean trimWSP) {
         if (DEBUG)
@@ -108,14 +116,18 @@
     }
 
     public TagValue(String data) {
+        tagValues = newTagValue();
         init();
         parse(data);
     }
 
-    protected void init() {
+    protected Map newTagValue() {
         // extensions may override this to use TreeMaps in order to keep track
         // of orders
-        tagValues = new HashMap();
+        return new HashMap();
+    }
+
+    protected void init() {
     }
 
     /**
@@ -171,6 +183,7 @@
             tagValues.put(tagString, value);
             i = next;
         }
+        this.stringRepresentation  = data;
     }
 
     public int hashCode() {
@@ -208,6 +221,12 @@
         else
             return val;
     }
+    
+    protected void setValue(String tag, String value) {
+        stringRepresentation = null;
+        tagValues.put(tag, value);
+    }
+
 
     protected CharSequence getDefault(String key) {
         return (CharSequence) defaults.get(key);
@@ -250,6 +269,14 @@
     }
 
     public String toString() {
+        if (stringRepresentation == null) {
+            updateStringRepresentation();
+        }
+        return stringRepresentation;
+    }
+    
+    private void updateStringRepresentation() {
+        // calculate a new string representation
         StringBuffer res = new StringBuffer();
         Set s = getTags();
         for (Iterator i = s.iterator(); i.hasNext();) {
@@ -259,7 +286,8 @@
             res.append(getValue(tag));
             res.append("; ");
         }
-        return res.toString();
+        // TODO add folding
+        stringRepresentation = res.toString();
     }
 
 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to