1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.james.jdkim.tagvalue;
21
22 import java.security.KeyFactory;
23 import java.security.NoSuchAlgorithmException;
24 import java.security.PublicKey;
25 import java.security.interfaces.RSAPublicKey;
26 import java.security.spec.InvalidKeySpecException;
27 import java.security.spec.X509EncodedKeySpec;
28 import java.util.ArrayList;
29 import java.util.LinkedHashMap;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.regex.Pattern;
33
34 import org.apache.commons.codec.binary.Base64;
35 import org.apache.james.jdkim.api.PublicKeyRecord;
36
37 public class PublicKeyRecordImpl extends TagValue implements PublicKeyRecord {
38
39 private static final String atom = "[a-zA-Z0-9!#$%&'*+/=?^_`{}|~-]+";
40
41 private static final String dotAtomText = "(" + atom + ")?\\*?(" + atom
42 + ")?";
43 private static final Pattern granularityPattern = Pattern.compile("^"
44 + dotAtomText + "$");
45
46
47 private static Pattern hyphenatedWordPattern = Pattern
48 .compile("^[a-zA-Z]([a-zA-Z0-9-]*[a-zA-Z0-9])?$");
49
50 public PublicKeyRecordImpl(String data) {
51 super(data);
52 }
53
54 protected Map newTagValue() {
55
56
57 return new LinkedHashMap();
58 }
59
60 protected void init() {
61 mandatoryTags.add("p");
62 defaults.put("v", "DKIM1");
63 defaults.put("g", "*");
64 defaults.put("h", ANY);
65 defaults.put("k", "rsa");
66 defaults.put("s", "*");
67 defaults.put("t", "");
68 }
69
70
71
72 public void validate() {
73 super.validate();
74 if (containsTag("v")) {
75
76 String firstKey = (String) tagSet().iterator().next();
77 if (!"v".equals(firstKey))
78 throw new IllegalStateException(
79 "Existing v= tag MUST be the first in the record list ("
80 + firstKey + ")");
81 }
82 if (!"DKIM1".equals(getValue("v")))
83 throw new IllegalStateException(
84 "Unknown version for v= (expected DKIM1): " + getValue("v"));
85 if ("".equals(getValue("p")))
86 throw new IllegalStateException("Revoked key. 'p=' in record");
87 }
88
89
90
91
92 public boolean isHashMethodSupported(CharSequence hash) {
93 List hashes = getAcceptableHashMethods();
94 if (hashes == null)
95 return true;
96 return isInListCaseInsensitive(hash, hashes);
97 }
98
99
100
101
102 public boolean isKeyTypeSupported(CharSequence hash) {
103 List hashes = getAcceptableKeyTypes();
104 return isInListCaseInsensitive(hash, hashes);
105 }
106
107
108
109
110 public List
111 if (ANY.equals(getValue("h")))
112 return null;
113 return stringToColonSeparatedList(getValue("h").toString(),
114 hyphenatedWordPattern);
115 }
116
117
118
119
120 public List
121 return stringToColonSeparatedList(getValue("k").toString(),
122 hyphenatedWordPattern);
123 }
124
125
126
127
128 public Pattern getGranularityPattern() {
129 String g = getValue("g").toString();
130 int pStar = g.indexOf('*');
131 if (VALIDATION) {
132 if (!granularityPattern.matcher(g).matches())
133 throw new IllegalStateException("Syntax error in granularity: "
134 + g);
135 }
136 if (g.length() == 0) {
137
138
139
140
141 return Pattern.compile("@");
142 } else if (pStar != -1) {
143 if (g.indexOf('*', pStar + 1) != -1)
144 throw new IllegalStateException(
145 "Invalid granularity using more than one wildcard: "
146 + g);
147 String pattern = "^\\Q" + g.subSequence(0, pStar).toString()
148 + "\\E.*\\Q"
149 + g.subSequence(pStar + 1, g.length()).toString() + "\\E$";
150 return Pattern.compile(pattern);
151 } else {
152
153
154 return Pattern.compile("^\\Q" + g + "\\E$");
155 }
156 }
157
158 public List getFlags() {
159 String flags = getValue("t").toString();
160 String[] flagsStrings = flags.split(":");
161 List res = new ArrayList();
162 for (int i = 0; i < flagsStrings.length; i++) {
163 res.add(trimFWS(flagsStrings[i], 0, flagsStrings[i].length() - 1,
164 true).toString());
165 }
166 return res;
167 }
168
169 public boolean isDenySubdomains() {
170 return getFlags().contains("s");
171 }
172
173 public boolean isTesting() {
174 return getFlags().contains("y");
175 }
176
177
178
179
180 public PublicKey getPublicKey() {
181 try {
182 String p = getValue("p").toString();
183 byte[] key = Base64.decodeBase64(p.getBytes());
184 KeyFactory keyFactory;
185 keyFactory = KeyFactory.getInstance(getValue("k").toString());
186 X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(key);
187 RSAPublicKey rsaKey;
188 rsaKey = (RSAPublicKey) keyFactory.generatePublic(pubSpec);
189 return rsaKey;
190 } catch (NoSuchAlgorithmException e) {
191 throw new IllegalStateException("Unknown algorithm: "
192 + e.getMessage());
193 } catch (InvalidKeySpecException e) {
194 throw new IllegalStateException("Invalid key spec: "
195 + e.getMessage());
196 }
197 }
198
199 }