View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.james.jdkim;
21  
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.OutputStream;
25  import java.security.Signature;
26  import java.security.SignatureException;
27  import java.util.HashMap;
28  import java.util.Iterator;
29  import java.util.List;
30  import java.util.Map;
31  
32  import org.apache.james.jdkim.api.Headers;
33  import org.apache.james.jdkim.api.SignatureRecord;
34  import org.apache.james.jdkim.exceptions.PermFailException;
35  
36  public abstract class DKIMCommon {
37  
38      private static final boolean DEEP_DEBUG = false;
39  
40      protected static void updateSignature(Signature signature, boolean relaxed,
41              CharSequence header, String fv) throws SignatureException {
42          if (relaxed) {
43              if (DEEP_DEBUG)
44                  System.out
45                          .println("#" + header.toString().toLowerCase() + ":-");
46              signature.update(header.toString().toLowerCase().getBytes());
47              signature.update(":".getBytes());
48              String headerValue = fv.substring(fv.indexOf(':') + 1);
49              headerValue = headerValue.replaceAll("\r\n[\t ]", " ");
50              headerValue = headerValue.replaceAll("[\t ]+", " ");
51              headerValue = headerValue.trim();
52              signature.update(headerValue.getBytes());
53              if (DEEP_DEBUG)
54                  System.out.println("#" + headerValue + "#");
55          } else {
56              signature.update(fv.getBytes());
57              if (DEEP_DEBUG)
58                  System.out.println("#" + fv + "#");
59          }
60      }
61  
62      protected static void signatureCheck(Headers h, SignatureRecord sign,
63              List headers, Signature signature)
64              throws SignatureException, PermFailException {
65  
66          boolean relaxedHeaders = SignatureRecord.RELAXED.equals(sign
67                  .getHeaderCanonicalisationMethod());
68          if (!relaxedHeaders
69                  && !SignatureRecord.SIMPLE.equals(sign
70                          .getHeaderCanonicalisationMethod())) {
71              throw new PermFailException(
72                      "Unsupported canonicalization algorythm: "
73                              + sign.getHeaderCanonicalisationMethod());
74          }
75  
76          // NOTE: this could be improved by using iterators.
77          // NOTE: this relies on the list returned by Message being in insertion
78          // order
79          Map/* String, Integer */processedHeader = new HashMap();
80  
81          for (Iterator i = headers.iterator(); i.hasNext();) {
82              CharSequence header = (CharSequence) i.next();
83              // NOTE check this getter is case insensitive
84              List hl = h.getFields(header.toString());
85              if (hl != null && hl.size() > 0) {
86                  Integer done = (Integer) processedHeader.get(header.toString());
87                  if (done == null)
88                      done = new Integer(0); /* Integer.valueOf(0) */
89                  int doneHeaders = done.intValue() + 1;
90                  if (doneHeaders <= hl.size()) {
91                      String fv = (String) hl.get(hl.size() - doneHeaders);
92                      updateSignature(signature, relaxedHeaders, header, fv);
93                      signature.update("\r\n".getBytes());
94                      processedHeader.put(header.toString(), new Integer(
95                              doneHeaders));
96                  }
97              }
98          }
99  
100         String signatureStub = "DKIM-Signature:" + sign.toUnsignedString();
101         updateSignature(signature, relaxedHeaders, "dkim-signature",
102                 signatureStub);
103     }
104 
105     public static void streamCopy(InputStream bodyIs, OutputStream out)
106             throws IOException {
107         byte[] buffer = new byte[2048];
108         int read;
109         while ((read = bodyIs.read(buffer)) > 0) {
110             out.write(buffer, 0, read);
111         }
112         bodyIs.close();
113         out.close();
114     }
115 
116 }