1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 /**
19 * @author Vladimir N. Molotkov
20 * @version $Revision$
21 */
22 
23 package tests.security.cert;
24 
25 import java.io.ByteArrayInputStream;
26 import java.io.IOException;
27 import java.io.ObjectStreamException;
28 import java.security.InvalidAlgorithmParameterException;
29 import java.security.InvalidKeyException;
30 import java.security.NoSuchAlgorithmException;
31 import java.security.NoSuchProviderException;
32 import java.security.Provider;
33 import java.security.PublicKey;
34 import java.security.Security;
35 import java.security.Signature;
36 import java.security.SignatureException;
37 import java.security.cert.Certificate;
38 import java.security.cert.CertificateEncodingException;
39 import java.security.cert.CertificateException;
40 import java.security.cert.CertificateFactory;
41 import java.util.Arrays;
42 import junit.framework.TestCase;
43 import org.apache.harmony.security.tests.support.cert.MyCertificate;
44 import org.apache.harmony.security.tests.support.cert.MyFailingCertificate;
45 import org.apache.harmony.security.tests.support.cert.TestUtils;
46 import org.apache.harmony.testframework.serialization.SerializationTest;
47 
48 /**
49  * Tests for <code>Certificate</code> fields and methods
50  *
51  */
52 public class CertificateTest extends TestCase {
53     /**
54      * Meaningless cert encoding just for testing purposes
55      */
56     private static final byte[] testEncoding = new byte[] { (byte) 1, (byte) 2,
57             (byte) 3, (byte) 4, (byte) 5 };
58 
59     /**
60      * Test for <code>Certificate(String type)</code> method<br>
61      */
testCertificate()62     public final void testCertificate() throws Exception {
63         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
64         assertTrue(Arrays.equals(testEncoding, c1.getEncoded()));
65         assertEquals("TEST", c1.getPublicKey().getAlgorithm());
66         assertTrue(Arrays.equals(new byte[] { (byte) 1, (byte) 2, (byte) 3 },
67                                  c1.getPublicKey().getEncoded()));
68         assertEquals("TEST_FORMAT", c1.getPublicKey().getFormat());
69         assertEquals("TEST_TYPE", c1.getType());
70     }
71 
72     /**
73      * Test for <code>hashCode()</code> method<br>
74      * Assertion: returns hash of the <code>Certificate</code> instance
75      * @throws CertificateEncodingException
76      */
testHashCode()77     public final void testHashCode() throws CertificateEncodingException {
78         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
79         Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding);
80 
81         assertTrue(c1.hashCode() == c2.hashCode());
82 
83         assertFalse(c1.hashCode() == new MyCertificate("TEST_TYPE", cert
84                 .getEncoded()).hashCode());
85         assertFalse(c1.hashCode() == cert.hashCode());
86     }
87 
88     /**
89      * Test for <code>hashCode()</code> method<br>
90      * Assertion: hash code of equal objects should be the same
91      */
testHashCodeEqualsObject()92     public final void testHashCodeEqualsObject() {
93         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
94         Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding);
95 
96         assertTrue((c1.hashCode() == c2.hashCode()) && c1.equals(c2));
97         assertFalse(cert.equals(c1));
98     }
99 
100     /**
101      * Test for <code>hashCode()</code> method<br>
102      * Assertion: returns the value computed with the algorithm in jdk8u60.
103      */
testHashCodeValue()104     public final void testHashCodeValue() {
105         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
106         // Result used to be 40 prior to jdk8u60.
107         assertEquals(29615266, c1.hashCode());
108     }
109 
110     /**
111      * Test for <code>getType()</code> method<br>
112      * Assertion: returns this certificate type
113      */
testGetType()114     public final void testGetType() {
115         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
116         assertEquals("TEST_TYPE", c1.getType());
117     }
118 
119     /**
120      * Test #1 for <code>equals(Object)</code> method<br>
121      * Assertion: object equals to itself
122      */
testEqualsObject01()123     public final void testEqualsObject01() {
124         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
125         assertTrue(c1.equals(c1));
126     }
127 
128     /**
129      * Test for <code>equals(Object)</code> method<br>
130      * Assertion: object equals to other <code>Certificate</code>
131      * instance with the same state
132      */
testEqualsObject02()133     public final void testEqualsObject02() {
134         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
135         Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding);
136         assertTrue(c1.equals(c2) && c2.equals(c1));
137     }
138 
139     /**
140      * Test for <code>equals(Object)</code> method<br>
141      * Assertion: object not equals to <code>null</code>
142      */
testEqualsObject03()143     public final void testEqualsObject03() {
144         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
145         assertFalse(c1.equals(null));
146     }
147 
148     /**
149      * Test for <code>equals(Object)</code> method<br>
150      * Assertion: object not equals to other which is not
151      * instance of <code>Certificate</code>
152      */
testEqualsObject04()153     public final void testEqualsObject04() {
154         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
155         assertFalse(c1.equals("TEST_TYPE"));
156     }
157 
158     // the following tests just call methods
159     // that are abstract in <code>Certificate</code>
160     // (So they just like signature tests)
161 
162     /**
163      * This test just calls <code>getEncoded()</code> method<br>
164      * @throws CertificateException
165      */
testGetEncoded()166     public final void testGetEncoded() throws CertificateException {
167         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
168         assertNotNull(c1.getEncoded());
169         assertTrue(Arrays.equals(testEncoding,c1.getEncoded()));
170 
171         CertificateFactory cf = CertificateFactory.getInstance("X.509");
172         byte[] expectedEncoding = cert.getEncoded();
173         Certificate actual = cf.generateCertificate(new ByteArrayInputStream(expectedEncoding));
174         byte[] actualEncoding = actual.getEncoded();
175         assertTrue(Arrays.equals(expectedEncoding, actualEncoding));
176 
177         assertFalse(expectedEncoding[4] == (byte) 200);
178         expectedEncoding[4] = (byte) 200;
179         try {
180             cf.generateCertificate(new ByteArrayInputStream(expectedEncoding));
181             fail();
182         } catch (CertificateException expected) {
183         }
184     }
185 
186     /**
187      * <code>verify(PublicKey)</code> with null args
188      *
189      * @throws InvalidKeyException
190      * @throws CertificateException
191      * @throws NoSuchAlgorithmException
192      * @throws NoSuchProviderException
193      * @throws SignatureException
194      */
testVerifyPublicKey()195     public final void testVerifyPublicKey()
196         throws InvalidKeyException,
197                CertificateException,
198                NoSuchAlgorithmException,
199                NoSuchProviderException,
200                SignatureException {
201         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
202         c1.verify(null);
203     }
204 
205     /**
206      * <code>verify(PublicKey,String)</code> with null args
207      *
208      * @throws InvalidKeyException
209      * @throws CertificateException
210      * @throws NoSuchAlgorithmException
211      * @throws NoSuchProviderException
212      * @throws SignatureException
213      */
testVerifyPublicKeyString()214     public final void testVerifyPublicKeyString()
215         throws InvalidKeyException,
216                CertificateException,
217                NoSuchAlgorithmException,
218                NoSuchProviderException,
219                SignatureException {
220         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
221         c1.verify((PublicKey) null, (String) null);
222     }
223 
224     /**
225      * <code>verify(PublicKey,Provider)</code> with null args
226      *
227      * @throws InvalidKeyException
228      * @throws CertificateException
229      * @throws NoSuchAlgorithmException
230      * @throws NoSuchProviderException
231      * @throws SignatureException
232      */
testVerifyPublicKeyProvider()233     public final void testVerifyPublicKeyProvider()
234         throws Exception  {
235         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
236         try {
237             // Android-changed: throw UOE instead of infinite recursion.
238             c1.verify((PublicKey) null, (Provider) null);
239             fail();
240         } catch(UnsupportedOperationException expected) {}
241     }
242 
243     /**
244      * This test just calls <code>toString()</code> method<br>
245      */
testToString()246     public final void testToString() {
247         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
248         c1.toString();
249     }
250 
251     /**
252      * This test just calls <code>testGetPublicKey()</code> method<br>
253      */
testGetPublicKey()254     public final void testGetPublicKey() {
255         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
256         c1.getPublicKey();
257     }
258 
259     /**
260      * This test just calls <code>writeReplace()</code> method<br>
261      */
testWriteReplace()262     public final void testWriteReplace() throws Exception {
263         MyCertificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
264         Object obj = c1.writeReplace();
265         assertTrue(obj.toString().contains("java.security.cert.Certificate$CertificateRep"));
266     }
267 
268 public class MyModifiablePublicKey implements PublicKey {
269 
270         private PublicKey key;
271         private boolean modifiedAlgo;
272         private String algo;
273         private String format;
274         private boolean modifiedFormat;
275         private boolean modifiedEncoding;
276         private byte[] encoding;
277 
MyModifiablePublicKey(PublicKey k)278         public MyModifiablePublicKey(PublicKey k) {
279             super();
280             this.key = k;
281         }
282 
getAlgorithm()283         public String getAlgorithm() {
284             if (modifiedAlgo) {
285                 return algo;
286             } else {
287                 return key.getAlgorithm();
288             }
289         }
290 
getFormat()291         public String getFormat() {
292             if (modifiedFormat) {
293                 return this.format;
294             } else {
295                 return key.getFormat();
296             }
297 
298         }
299 
getEncoded()300         public byte[] getEncoded() {
301             if (modifiedEncoding) {
302                 return this.encoding;
303             } else {
304                 return key.getEncoded();
305             }
306 
307         }
308 
getSerVerUID()309         public long getSerVerUID() {
310             return key.serialVersionUID;
311         }
312 
setAlgorithm(String myAlgo)313         public void setAlgorithm(String myAlgo) {
314             modifiedAlgo = true;
315             this.algo = myAlgo;
316         }
317 
setFormat(String myFormat)318         public void setFormat(String myFormat) {
319             modifiedFormat = true;
320             format = myFormat;
321         }
322 
setEncoding(byte[] myEncoded)323         public void setEncoding(byte[] myEncoded) {
324             modifiedEncoding = true;
325             encoding = myEncoded;
326         }
327     }
328 
329     private Certificate cert;
330 
setUp()331     public void setUp() throws Exception {
332         super.setUp();
333         TestUtils.initCertPathSSCertChain();
334         cert = TestUtils.rootCertificateSS;
335     }
336 
337     /**
338      * This test just calls <code>verify(PublicKey,String)</code> method<br>
339      *
340      * @throws InvalidKeyException
341      * @throws CertificateException
342      * @throws NoSuchAlgorithmException
343      * @throws NoSuchProviderException
344      * @throws SignatureException
345      */
testVerifyPublicKeyString2()346     public final void testVerifyPublicKeyString2() throws InvalidKeyException,
347             CertificateException, NoSuchAlgorithmException,
348             NoSuchProviderException, SignatureException {
349 
350         final Signature sig = Signature.getInstance("SHA1WithRSA");
351         sig.initVerify(cert.getPublicKey());
352         final Provider provider = sig.getProvider();
353         // real test
354         cert.verify(cert.getPublicKey(), provider.getName());
355 
356         // Exception tests
357 
358         try {
359             cert.verify(cert.getPublicKey(), "UnknownProvider");
360             fail();
361         } catch (NoSuchProviderException expected) {
362         }
363 
364         // This test has side effects affecting all other tests running later
365         // on in the same vm instance. Maybe a better way would be to first add
366         // a new provider, test if it works, then remove it and test if the
367         // exception is thrown.
368         //
369         // CertificateFactory cf = CertificateFactory.getInstance("X.509");
370         // Provider wrongProvider = cf.getProvider();
371         //
372         // Security.removeProvider(wrongProvider.getName());
373         //
374         // try {
375         //     cert.verify(cert.getPublicKey(), wrongProvider.getName());
376         //     fail();
377         // } catch (NoSuchAlgorithmException expected) {
378         // }
379         //
380         // Security.insertProviderAt(wrongProvider, oldPosition);
381 
382         /*
383         PublicKey k = cert.getPublicKey();
384         MyModifiablePublicKey tamperedKey = new MyModifiablePublicKey(k);
385         tamperedKey.setAlgorithm("wrongAlgo");
386 
387         try {
388             cert.verify(tamperedKey, provs[0].getName());
389             fail();
390         } catch (SignatureException expected) {
391         }
392 
393         try {
394             cert.verify(c1.getPublicKey(), provs[0].getName());
395             fail();
396         } catch (InvalidKeyException expected) {
397         }
398         */
399     }
400 
testVerifyPublicKeyProvider2()401     public final void testVerifyPublicKeyProvider2() throws Exception {
402         final Signature sig = Signature.getInstance("SHA1WithRSA");
403         sig.initVerify(cert.getPublicKey());
404         final Provider provider = sig.getProvider();
405         cert.verify(cert.getPublicKey(), provider);
406         // equivalent to calling cert.verify(cert.getPublicKey())
407         cert.verify(cert.getPublicKey(), (Provider)null);
408     }
409 
410     /**
411      * This test just calls <code>verify(PublicKey)</code> method<br>
412      *
413      * @throws InvalidKeyException
414      * @throws CertificateException
415      * @throws NoSuchAlgorithmException
416      * @throws NoSuchProviderException
417      * @throws SignatureException
418      * @throws IOException
419      * @throws InvalidAlgorithmParameterException
420      */
testVerifyPublicKey2()421     public final void testVerifyPublicKey2()
422             throws InvalidKeyException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException, InvalidAlgorithmParameterException, IOException {
423 
424         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
425         c1.verify(null);
426 
427         cert.verify(cert.getPublicKey());
428 
429         PublicKey k = cert.getPublicKey();
430 
431         MyModifiablePublicKey changedEncoding = new MyModifiablePublicKey(k);
432         changedEncoding.setEncoding(new byte[cert.getEncoded().length - 1]);
433 
434         try {
435             cert.verify(c1.getPublicKey());
436             fail();
437         } catch (InvalidKeyException expected) {
438         }
439 
440         try {
441             cert.verify(changedEncoding);
442             fail();
443         } catch (Exception expected) {
444         }
445     }
446 
447     /**
448      * This test just calls <code>writeReplace()</code> method<br>
449      */
testWriteReplace2()450     public final void testWriteReplace2() {
451         MyCertificate c1 = new MyFailingCertificate("TEST_TYPE", testEncoding);
452 
453         try {
454             c1.writeReplace();
455             fail();
456         } catch (ObjectStreamException expected) {
457         }
458     }
459 
460     /**
461      * serialization/deserialization compatibility.
462      */
testSerializationSelf()463     public void testSerializationSelf() throws Exception {
464         TestUtils.initCertPathSSCertChain();
465 
466         SerializationTest.verifySelf(TestUtils.rootCertificateSS);
467     }
468 
469     /**
470      * serialization/deserialization compatibility with RI.
471      */
testSerializationCompatibility()472     public void testSerializationCompatibility() throws Exception {
473         // create test file (once)
474         // SerializationTest.createGoldenFile("/sdcard", this, TestUtils.rootCertificateSS);
475         TestUtils.initCertPathSSCertChain();
476 
477         SerializationTest.verifyGolden(this, TestUtils.rootCertificateSS);
478     }
479 }
480