Home | History | Annotate | Download | only in cert
      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      */
     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      */
     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      */
     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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    278         public MyModifiablePublicKey(PublicKey k) {
    279             super();
    280             this.key = k;
    281         }
    282 
    283         public String getAlgorithm() {
    284             if (modifiedAlgo) {
    285                 return algo;
    286             } else {
    287                 return key.getAlgorithm();
    288             }
    289         }
    290 
    291         public String getFormat() {
    292             if (modifiedFormat) {
    293                 return this.format;
    294             } else {
    295                 return key.getFormat();
    296             }
    297 
    298         }
    299 
    300         public byte[] getEncoded() {
    301             if (modifiedEncoding) {
    302                 return this.encoding;
    303             } else {
    304                 return key.getEncoded();
    305             }
    306 
    307         }
    308 
    309         public long getSerVerUID() {
    310             return key.serialVersionUID;
    311         }
    312 
    313         public void setAlgorithm(String myAlgo) {
    314             modifiedAlgo = true;
    315             this.algo = myAlgo;
    316         }
    317 
    318         public void setFormat(String myFormat) {
    319             modifiedFormat = true;
    320             format = myFormat;
    321         }
    322 
    323         public void setEncoding(byte[] myEncoded) {
    324             modifiedEncoding = true;
    325             encoding = myEncoded;
    326         }
    327     }
    328 
    329     private Certificate cert;
    330 
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    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