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.math.BigInteger;
23  import java.security.PublicKey;
24  import java.security.interfaces.RSAKey;
25  import java.util.List;
26  import java.util.regex.Pattern;
27  
28  import org.apache.james.jdkim.api.PublicKeyRecord;
29  import org.apache.james.jdkim.tagvalue.PublicKeyRecordImpl;
30  
31  import junit.framework.TestCase;
32  
33  public class PublicKeyRecordTest extends TestCase {
34  
35      public void testValidate() {
36          PublicKeyRecord pkr = new PublicKeyRecordImpl("");
37          try {
38              pkr.validate();
39              fail("Expected failure: missing mandatory parameters");
40          } catch (IllegalStateException e) {
41          }
42          pkr = new PublicKeyRecordImpl("k=rsa; p=XXXXXXXX=;");
43          pkr.validate();
44          pkr = new PublicKeyRecordImpl("v=DKIM1; k=rsa; p=XXXXXX=");
45          pkr.validate();
46          pkr = new PublicKeyRecordImpl(" v=DKIM1; k=rsa; p=XXXXXX=");
47          pkr.validate();
48          pkr = new PublicKeyRecordImpl("k=rsa; v=DKIM1; p=XXXXXX=");
49          try {
50              pkr.validate();
51              fail("Expected failure: v should be the first");
52          } catch (IllegalStateException e) {
53          }
54          pkr = new PublicKeyRecordImpl("v=DKIM2; k=rsa; p=XXXXXX=");
55          try {
56              pkr.validate();
57              fail("Expected failure: wrong version");
58          } catch (IllegalStateException e) {
59          }
60          pkr = new PublicKeyRecordImpl("v=DKIM1; k=rsa; p=");
61          try {
62              pkr.validate();
63              fail("Expected failure: revoked key");
64          } catch (IllegalStateException e) {
65          }
66      }
67  
68      public void testIsHashMethodSupported() {
69          PublicKeyRecord pkr = new PublicKeyRecordImpl("k=rsa; p=XXXXXXXX=;");
70          pkr.validate();
71          assertTrue(pkr.isHashMethodSupported("sha1"));
72          assertTrue(pkr.isHashMethodSupported("sha256"));
73          pkr = new PublicKeyRecordImpl("k=rsa; h=sha1:sha256; p=XXXXXXXX=;");
74          pkr.validate();
75          assertTrue(pkr.isHashMethodSupported("sha1"));
76          assertFalse(pkr.isHashMethodSupported("sha128"));
77          assertTrue(pkr.isHashMethodSupported("sha256"));
78      }
79  
80      public void testIsKeyTypeSupported() {
81          PublicKeyRecord pkr = new PublicKeyRecordImpl("k=rsa; p=XXXXXXXX=;");
82          pkr.validate();
83          assertTrue(pkr.isKeyTypeSupported("rsa"));
84          assertFalse(pkr.isKeyTypeSupported("dsa"));
85      }
86  
87      public void testGetAcceptableHashMethods() {
88          PublicKeyRecord pkr = new PublicKeyRecordImpl(
89                  "k=rsa; h=sha1:sha256; p=XXXXXXXX=;");
90          pkr.validate();
91          List methods = pkr.getAcceptableHashMethods();
92          assertEquals("[sha1, sha256]", methods.toString());
93          pkr = new PublicKeyRecordImpl("k=rsa; p=XXXXXXXX=;");
94          pkr.validate();
95          methods = pkr.getAcceptableHashMethods();
96          assertNull(methods);
97      }
98  
99      public void testGetAcceptableKeyTypes() {
100         PublicKeyRecord pkr = new PublicKeyRecordImpl(
101                 "k=rsa; h=sha1:sha256; p=XXXXXXXX=;");
102         pkr.validate();
103         List methods = pkr.getAcceptableKeyTypes();
104         assertEquals("[rsa]", methods.toString());
105         pkr = new PublicKeyRecordImpl("k=rsa:dsa; p=XXXXXXXX=;");
106         pkr.validate();
107         methods = pkr.getAcceptableKeyTypes();
108         assertEquals("[rsa, dsa]", methods.toString());
109     }
110 
111     public void testGetGranularityPattern() {
112         PublicKeyRecord pkr = new PublicKeyRecordImpl(
113                 "k=rsa; h=sha1:sha256; p=XXXXXXXX=;");
114         pkr.validate();
115         Pattern pattern = pkr.getGranularityPattern();
116         assertEquals("^\\Q\\E.*\\Q\\E$", pattern.pattern());
117         assertTrue(pattern.matcher("something").matches());
118         assertTrue(pattern.matcher("").matches());
119         pkr = new PublicKeyRecordImpl("k=rsa; g=; h=sha1:sha256; p=XXXXXXXX=;");
120         pkr.validate();
121         pattern = pkr.getGranularityPattern();
122         assertEquals("@", pattern.pattern());
123         assertFalse(pattern.matcher("something").matches());
124         assertFalse(pattern.matcher("").matches());
125         pkr = new PublicKeyRecordImpl(
126                 "k=rsa; g=some*; h=sha1:sha256; p=XXXXXXXX=;");
127         pkr.validate();
128         pattern = pkr.getGranularityPattern();
129         assertTrue(pattern.matcher("something").matches());
130         assertTrue(pattern.matcher("some").matches());
131         assertFalse(pattern.matcher("som").matches());
132         assertFalse(pattern.matcher("awesome").matches());
133         assertEquals("^\\Qsome\\E.*\\Q\\E$", pattern.pattern());
134         pkr = new PublicKeyRecordImpl(
135                 "k=rsa; g=*+test; h=sha1:sha256; p=XXXXXXXX=;");
136         pkr.validate();
137         pattern = pkr.getGranularityPattern();
138         assertEquals("^\\Q\\E.*\\Q+test\\E$", pattern.pattern());
139         assertTrue(pattern.matcher("a+test").matches());
140         assertTrue(pattern.matcher("+test").matches());
141         assertFalse(pattern.matcher("atest").matches());
142         assertFalse(pattern.matcher("+tested").matches());
143         pkr = new PublicKeyRecordImpl(
144                 "k=rsa; g=test; h=sha1:sha256; p=XXXXXXXX=;");
145         pkr.validate();
146         pattern = pkr.getGranularityPattern();
147         assertEquals("^\\Qtest\\E$", pattern.pattern());
148         assertTrue(pattern.matcher("test").matches());
149         assertFalse(pattern.matcher("atest").matches());
150         assertFalse(pattern.matcher("testa").matches());
151         try {
152             pkr = new PublicKeyRecordImpl(
153                     "k=rsa; g=*\\+test; h=sha1:sha256; p=XXXXXXXX=;");
154             pkr.validate();
155             pattern = pkr.getGranularityPattern();
156             fail("Expected syntax error");
157         } catch (IllegalStateException e) {
158         }
159         try {
160             pkr = new PublicKeyRecordImpl(
161                     "k=rsa; g=*test*; h=sha1:sha256; p=XXXXXXXX=;");
162             pkr.validate();
163             pattern = pkr.getGranularityPattern();
164             fail("Expected syntax error");
165         } catch (IllegalStateException e) {
166         }
167     }
168 
169     public void testGetPublicKey() {
170         PublicKeyRecord pkr = new PublicKeyRecordImpl(
171                 "k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
172         pkr.validate();
173         PublicKey pk = pkr.getPublicKey();
174         assertEquals("RSA", pk.getAlgorithm());
175         // On older jvm this is X509
176         // assertEquals("X.509", pk.getFormat());
177         assertEquals(
178                 new BigInteger(
179                         "140815480285950232210124449496973988135931539914762288985377502488754711434253259186192434865594456027796377309280714060984552676169392598862819043219650259702261370701494928576447797673342985377518637829874968725582762257956980427968667812066816497848410406856165942400151628259779523949079651036806330485849"),
180                 ((RSAKey) pk).getModulus());
181 
182         try {
183             pkr = new PublicKeyRecordImpl(
184                     "k=dsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
185             pkr.validate();
186             pk = pkr.getPublicKey();
187             fail("Expected invalid key spec. DSA is not supported");
188         } catch (IllegalStateException e) {
189         }
190 
191         try {
192             pkr = new PublicKeyRecordImpl(
193                     "k=unknown; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
194             pkr.validate();
195             pk = pkr.getPublicKey();
196             fail("Expected invalid algorythm. 'unknown' is not supported");
197         } catch (IllegalStateException e) {
198         }
199     }
200 
201     public void testGetFlags() {
202         PublicKeyRecord pkr = new PublicKeyRecordImpl(
203                 "k=rsa; t=y:s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
204         pkr.validate();
205         List flags = pkr.getFlags();
206         assertEquals("[y, s]", flags.toString());
207         pkr = new PublicKeyRecordImpl(
208                 "k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
209         pkr.validate();
210         flags = pkr.getFlags();
211         assertEquals("[y]", flags.toString());
212         pkr = new PublicKeyRecordImpl(
213                 "k=rsa; t=; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
214         pkr.validate();
215         flags = pkr.getFlags();
216         assertEquals("[]", flags.toString());
217     }
218 
219     public void testIsTesting() {
220         PublicKeyRecord pkr = new PublicKeyRecordImpl(
221                 "k=rsa; t=y:s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
222         pkr.validate();
223         assertTrue(pkr.isTesting());
224         pkr = new PublicKeyRecordImpl(
225                 "k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
226         pkr.validate();
227         assertTrue(pkr.isTesting());
228         pkr = new PublicKeyRecordImpl(
229                 "k=rsa; t=; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
230         pkr.validate();
231         assertFalse(pkr.isTesting());
232     }
233 
234     public void testIsDenySubdomains() {
235         PublicKeyRecord pkr = new PublicKeyRecordImpl(
236                 "k=rsa; t=y:s; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
237         pkr.validate();
238         assertTrue(pkr.isDenySubdomains());
239         pkr = new PublicKeyRecordImpl(
240                 "k=rsa; t=y; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
241         pkr.validate();
242         assertFalse(pkr.isDenySubdomains());
243         pkr = new PublicKeyRecordImpl(
244                 "k=rsa; t=; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDIhyR3oItOy22ZOaBrIVe9m/iME3RqOJeasANSpg2YTHTYV+Xtp4xwf5gTjCmHQEMOs0qYu0FYiNQPQogJ2t0Mfx9zNu06rfRBDjiIU9tpx2T+NGlWZ8qhbiLo5By8apJavLyqTLavyPSrvsx0B3YzC63T4Age2CDqZYA+OwSMWQIDAQAB");
245         pkr.validate();
246         assertFalse(pkr.isDenySubdomains());
247     }
248 
249 }