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 
     26 
     27 import dalvik.annotation.AndroidOnly;
     28 import dalvik.annotation.KnownFailure;
     29 import dalvik.annotation.TestLevel;
     30 import dalvik.annotation.TestTargetNew;
     31 import dalvik.annotation.TestTargetClass;
     32 import dalvik.annotation.TestTargets;
     33 
     34 import junit.framework.TestCase;
     35 
     36 import java.io.ByteArrayInputStream;
     37 import java.io.IOException;
     38 import java.io.ObjectStreamException;
     39 import java.security.InvalidAlgorithmParameterException;
     40 import java.security.InvalidKeyException;
     41 import java.security.NoSuchAlgorithmException;
     42 import java.security.NoSuchProviderException;
     43 import java.security.Provider;
     44 import java.security.PublicKey;
     45 import java.security.Security;
     46 import java.security.SignatureException;
     47 import java.security.cert.Certificate;
     48 import java.security.cert.CertificateEncodingException;
     49 import java.security.cert.CertificateException;
     50 import java.security.cert.CertificateFactory;
     51 import java.util.Arrays;
     52 
     53 import org.apache.harmony.security.tests.support.cert.MyCertificate;
     54 import org.apache.harmony.security.tests.support.cert.MyFailingCertificate;
     55 import org.apache.harmony.security.tests.support.cert.TestUtils;
     56 import org.apache.harmony.testframework.serialization.SerializationTest;
     57 
     58 /**
     59  * Tests for <code>Certificate</code> fields and methods
     60  *
     61  */
     62 @TestTargetClass(Certificate.class)
     63 public class CertificateTest extends TestCase {
     64     /**
     65      * Meaningless cert encoding just for testing purposes
     66      */
     67     private static final byte[] testEncoding = new byte[] { (byte) 1, (byte) 2,
     68             (byte) 3, (byte) 4, (byte) 5 };
     69 
     70     //
     71     // Tests
     72     //
     73 
     74     /**
     75      * Test for <code>Certificate(String type)</code> method<br>
     76      */
     77     @TestTargetNew(
     78         level = TestLevel.SUFFICIENT,
     79         notes = "",
     80         method = "Certificate",
     81         args = {java.lang.String.class}
     82     )
     83     @AndroidOnly("Gets security providers with specific signature algorithm: " +
     84             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
     85     public final void testCertificate() {
     86         try {
     87             Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
     88             assertTrue(Arrays.equals(testEncoding, c1.getEncoded()));
     89             assertEquals("TEST", c1.getPublicKey().getAlgorithm());
     90             assertTrue(Arrays.equals(
     91                     new byte[] { (byte) 1, (byte) 2, (byte) 3 }, c1
     92                             .getPublicKey().getEncoded()));
     93             assertEquals("TEST_FORMAT", c1.getPublicKey().getFormat());
     94             assertEquals("TEST_TYPE", c1.getType());
     95         } catch (CertificateEncodingException e) {
     96             fail("Unexpected CertificateEncodingException " + e.getMessage());
     97         }
     98     }
     99 
    100     /**
    101      * Test for <code>hashCode()</code> method<br>
    102      * Assertion: returns hash of the <code>Certificate</code> instance
    103      * @throws CertificateEncodingException
    104      */
    105     @TestTargetNew(
    106         level = TestLevel.PARTIAL_COMPLETE,
    107         notes = "",
    108         method = "hashCode",
    109         args = {}
    110     )
    111     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    112             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    113     public final void testHashCode() throws CertificateEncodingException {
    114         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    115         Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding);
    116 
    117         assertTrue(c1.hashCode() == c2.hashCode());
    118 
    119         assertFalse(c1.hashCode() == new MyCertificate("TEST_TYPE", cert
    120                 .getEncoded()).hashCode());
    121         assertFalse(c1.hashCode() == cert.hashCode());
    122     }
    123 
    124     /**
    125      * Test for <code>hashCode()</code> method<br>
    126      * Assertion: hash code of equal objects should be the same
    127      */
    128     @TestTargetNew(
    129         level = TestLevel.PARTIAL_COMPLETE,
    130         notes = "",
    131         method = "hashCode",
    132         args = {}
    133     )
    134     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    135             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    136     public final void testHashCodeEqualsObject() {
    137         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    138         Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding);
    139 
    140         assertTrue((c1.hashCode() == c2.hashCode()) && c1.equals(c2));
    141         assertFalse(cert.equals(c1));
    142     }
    143 
    144 
    145     /**
    146      * Test for <code>getType()</code> method<br>
    147      * Assertion: returns this certificate type
    148      */
    149     @TestTargetNew(
    150         level = TestLevel.COMPLETE,
    151         notes = "",
    152         method = "getType",
    153         args = {}
    154     )
    155     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    156             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    157     public final void testGetType() {
    158         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    159         assertEquals("TEST_TYPE", c1.getType());
    160     }
    161 
    162     /**
    163      * Test #1 for <code>equals(Object)</code> method<br>
    164      * Assertion: object equals to itself
    165      */
    166     @TestTargetNew(
    167         level = TestLevel.PARTIAL_COMPLETE,
    168         notes = "Verifies positive case.",
    169         method = "equals",
    170         args = {java.lang.Object.class}
    171     )
    172     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    173             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    174     public final void testEqualsObject01() {
    175         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    176         assertTrue(c1.equals(c1));
    177     }
    178 
    179     /**
    180      * Test for <code>equals(Object)</code> method<br>
    181      * Assertion: object equals to other <code>Certificate</code>
    182      * instance with the same state
    183      */
    184     @TestTargetNew(
    185         level = TestLevel.PARTIAL_COMPLETE,
    186         notes = "Verifies positive case.",
    187         method = "equals",
    188         args = {java.lang.Object.class}
    189     )
    190     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    191             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    192     public final void testEqualsObject02() {
    193         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    194         Certificate c2 = new MyCertificate("TEST_TYPE", testEncoding);
    195         assertTrue(c1.equals(c2) && c2.equals(c1));
    196     }
    197 
    198     /**
    199      * Test for <code>equals(Object)</code> method<br>
    200      * Assertion: object not equals to <code>null</code>
    201      */
    202     @TestTargetNew(
    203         level = TestLevel.PARTIAL_COMPLETE,
    204         notes = "Verifies equals method with null as a parameter.",
    205         method = "equals",
    206         args = {java.lang.Object.class}
    207     )
    208     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    209             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    210     public final void testEqualsObject03() {
    211         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    212         assertFalse(c1.equals(null));
    213     }
    214 
    215     /**
    216      * Test for <code>equals(Object)</code> method<br>
    217      * Assertion: object not equals to other which is not
    218      * instance of <code>Certificate</code>
    219      */
    220     @TestTargetNew(
    221         level = TestLevel.PARTIAL_COMPLETE,
    222         notes = "Verifies negative case.",
    223         method = "equals",
    224         args = {java.lang.Object.class}
    225     )
    226     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    227             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    228     public final void testEqualsObject04() {
    229         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    230         assertFalse(c1.equals("TEST_TYPE"));
    231     }
    232 
    233     //
    234     // the following tests just call methods
    235     // that are abstract in <code>Certificate</code>
    236     // (So they just like signature tests)
    237     //
    238 
    239     /**
    240      * This test just calls <code>getEncoded()</code> method<br>
    241      * @throws CertificateException
    242      */
    243     @TestTargetNew(
    244         level = TestLevel.SUFFICIENT,
    245         notes = "Can not verify CertificateEncodingException. indirectly tested",
    246         method = "getEncoded",
    247         args = {}
    248     )
    249     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    250             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    251     @KnownFailure("Assertion does not evaluate to true... Works in javax.Certificate")
    252     public final void testGetEncoded() throws CertificateException {
    253         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    254         assertNotNull(c1.getEncoded());
    255 
    256         assertTrue(Arrays.equals(TestUtils.rootCert.getBytes(),cert.getEncoded()));
    257 
    258         byte[] b = TestUtils.rootCert.getBytes();
    259 
    260         b[4] = (byte) 200;
    261 
    262         try {
    263         CertificateFactory cf = CertificateFactory.getInstance("X.509");
    264         ByteArrayInputStream stream = new ByteArrayInputStream(b);
    265         cert = cf.generateCertificate(stream);
    266         } catch (CertificateException e) {
    267             //ok
    268         }
    269     }
    270 
    271     /**
    272      * This test just calls <code>verify(PublicKey)</code> method<br>
    273      *
    274      * @throws InvalidKeyException
    275      * @throws CertificateException
    276      * @throws NoSuchAlgorithmException
    277      * @throws NoSuchProviderException
    278      * @throws SignatureException
    279      */
    280     @TestTargetNew(
    281         level = TestLevel.PARTIAL_COMPLETE,
    282         notes = "Verifies only null as a parameter.",
    283         method = "verify",
    284         args = {java.security.PublicKey.class}
    285     )
    286     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    287             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    288     public final void testVerifyPublicKey()
    289         throws InvalidKeyException,
    290                CertificateException,
    291                NoSuchAlgorithmException,
    292                NoSuchProviderException,
    293                SignatureException {
    294         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    295         c1.verify(null);
    296     }
    297 
    298     /**
    299      * This test just calls <code>verify(PublicKey,String)</code> method<br>
    300      *
    301      * @throws InvalidKeyException
    302      * @throws CertificateException
    303      * @throws NoSuchAlgorithmException
    304      * @throws NoSuchProviderException
    305      * @throws SignatureException
    306      */
    307     @TestTargetNew(
    308         level = TestLevel.PARTIAL_COMPLETE,
    309         notes = "Verifies only null as parameters.",
    310         method = "verify",
    311         args = {java.security.PublicKey.class, java.lang.String.class}
    312     )
    313     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    314             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    315     public final void testVerifyPublicKeyString()
    316         throws InvalidKeyException,
    317                CertificateException,
    318                NoSuchAlgorithmException,
    319                NoSuchProviderException,
    320                SignatureException {
    321         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    322         c1.verify(null, null);
    323     }
    324 
    325     /**
    326      * This test just calls <code>toString()</code> method<br>
    327      */
    328     @TestTargetNew(
    329         level = TestLevel.COMPLETE,
    330         notes = "",
    331         method = "toString",
    332         args = {}
    333     )
    334     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    335             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    336     public final void testToString() {
    337         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    338         c1.toString();
    339     }
    340 
    341     /**
    342      * This test just calls <code>testGetPublicKey()</code> method<br>
    343      */
    344     @TestTargetNew(
    345         level = TestLevel.COMPLETE,
    346         notes = "",
    347         method = "getPublicKey",
    348         args = {}
    349     )
    350     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    351             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    352     public final void testGetPublicKey() {
    353         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    354         c1.getPublicKey();
    355     }
    356 
    357     /**
    358      * This test just calls <code>writeReplace()</code> method<br>
    359      */
    360     @TestTargetNew(
    361         level = TestLevel.PARTIAL_COMPLETE,
    362         notes = "Doesn't verify ObjectStreamException.",
    363         method = "writeReplace",
    364         args = {}
    365     )
    366     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    367             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    368     public final void testWriteReplace() {
    369         MyCertificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    370 
    371         try {
    372             Object obj = c1.writeReplace();
    373             assertTrue(obj.toString().contains(
    374                     "java.security.cert.Certificate$CertificateRep"));
    375         } catch (ObjectStreamException e) {
    376             fail("Unexpected ObjectStreamException " + e.getMessage());
    377         }
    378     }
    379 
    380 public class MyModifiablePublicKey implements PublicKey {
    381 
    382         private PublicKey key;
    383         private boolean modifiedAlgo;
    384         private String algo;
    385         private String format;
    386         private boolean modifiedFormat;
    387         private boolean modifiedEncoding;
    388         private byte[] encoding;
    389 
    390         public MyModifiablePublicKey(PublicKey k) {
    391             super();
    392             this.key = k;
    393         }
    394 
    395         public String getAlgorithm() {
    396             if (modifiedAlgo) {
    397                 return algo;
    398             } else {
    399                 return key.getAlgorithm();
    400             }
    401         }
    402 
    403         public String getFormat() {
    404             if (modifiedFormat) {
    405                 return this.format;
    406             } else {
    407                 return key.getFormat();
    408             }
    409 
    410         }
    411 
    412         public byte[] getEncoded() {
    413             if (modifiedEncoding) {
    414                 return this.encoding;
    415             } else {
    416                 return key.getEncoded();
    417             }
    418 
    419         }
    420 
    421         public long getSerVerUID() {
    422             return key.serialVersionUID;
    423         }
    424 
    425         public void setAlgorithm(String myAlgo) {
    426             modifiedAlgo = true;
    427             this.algo = myAlgo;
    428         }
    429 
    430         public void setFormat(String myFormat) {
    431             modifiedFormat = true;
    432             format = myFormat;
    433         }
    434 
    435         public void setEncoding(byte[] myEncoded) {
    436             modifiedEncoding = true;
    437             encoding = myEncoded;
    438         }
    439     }
    440 
    441     private Certificate cert;
    442 
    443     private Provider wrongProvider;
    444 
    445     private Provider useFulProvider;
    446 
    447     public void setUp() throws Exception {
    448         super.setUp();
    449         TestUtils.initCertPathSSCertChain();
    450         cert = TestUtils.rootCertificateSS;
    451         CertificateFactory cf = CertificateFactory.getInstance("X.509");
    452         wrongProvider = cf.getProvider();
    453         useFulProvider = Security.getProviders("Signature.sha1WithRSAEncryption")[0];
    454     }
    455 
    456     /**
    457      * This test just calls <code>verify(PublicKey,String)</code> method<br>
    458      *
    459      * @throws InvalidKeyException
    460      * @throws CertificateException
    461      * @throws NoSuchAlgorithmException
    462      * @throws NoSuchProviderException
    463      * @throws SignatureException
    464      */
    465     @TestTargetNew(
    466         level = TestLevel.SUFFICIENT,
    467         notes = "Test fails: ClassCastException when SignatureException is expected",
    468         method = "verify",
    469         args = {java.security.PublicKey.class, java.lang.String.class}
    470     )
    471     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    472             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    473     public final void testVerifyPublicKeyString2() throws InvalidKeyException,
    474             CertificateException, NoSuchAlgorithmException,
    475             NoSuchProviderException, SignatureException {
    476 
    477         // real test
    478         cert.verify(cert.getPublicKey(), useFulProvider.getName());
    479 
    480         // Exception tests
    481 
    482         try {
    483             cert.verify(cert.getPublicKey(), "UnknownProvider");
    484         } catch (NoSuchProviderException e) {
    485             // ok
    486         }
    487 
    488         // This test has side effects affecting all other tests running later
    489         // on in the same vm instance. Maybe a better way would be to first add
    490         // a new provider, test if it works, then remove it and test if the
    491         // exception is thrown.
    492         //
    493         // Security.removeProvider(wrongProvider.getName());
    494         //
    495         // try {
    496         //     cert.verify(cert.getPublicKey(), wrongProvider.getName());
    497         // } catch (NoSuchAlgorithmException e) {
    498         //     // ok
    499         // }
    500         //
    501         // Security.insertProviderAt(wrongProvider, oldPosition);
    502 
    503         /*
    504         PublicKey k = cert.getPublicKey();
    505         MyModifiablePublicKey tamperedKey = new MyModifiablePublicKey(k);
    506         tamperedKey.setAlgorithm("wrongAlgo");
    507 
    508         try {
    509             cert.verify(tamperedKey, provs[0].getName());
    510         } catch (SignatureException e) {
    511             // ok
    512         }
    513 
    514         try {
    515             cert.verify(c1.getPublicKey(), provs[0].getName());
    516         } catch (InvalidKeyException e) {
    517             // ok
    518         }
    519         */
    520     }
    521 
    522     /**
    523      * This test just calls <code>verify(PublicKey)</code> method<br>
    524      *
    525      * @throws InvalidKeyException
    526      * @throws CertificateException
    527      * @throws NoSuchAlgorithmException
    528      * @throws NoSuchProviderException
    529      * @throws SignatureException
    530      * @throws IOException
    531      * @throws InvalidAlgorithmParameterException
    532      */
    533     @TestTargetNew(
    534         level = TestLevel.SUFFICIENT,
    535         notes = "Can't test exception for cases where the algorithm is unknown",
    536         method = "verify",
    537         args = {java.security.PublicKey.class}
    538     )
    539     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    540             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    541     public final void testVerifyPublicKey2() throws InvalidKeyException,
    542             CertificateException, NoSuchAlgorithmException,
    543             NoSuchProviderException, SignatureException, InvalidAlgorithmParameterException, IOException {
    544 
    545         Certificate c1 = new MyCertificate("TEST_TYPE", testEncoding);
    546         c1.verify(null);
    547 
    548         cert.verify(cert.getPublicKey());
    549 
    550         PublicKey k = cert.getPublicKey();
    551 
    552         MyModifiablePublicKey changedEncoding = new MyModifiablePublicKey(k);
    553         changedEncoding
    554                 .setEncoding(new byte[cert.getEncoded().length - 1]);
    555 
    556         try {
    557             cert.verify(c1.getPublicKey());
    558             fail("expected InvalidKeyException");
    559         } catch (InvalidKeyException e) {
    560             // ok
    561         }
    562 
    563         try {
    564             cert.verify(changedEncoding);
    565             fail("Exception expected");
    566         } catch (Exception e) {
    567             // ok
    568         }
    569     }
    570 
    571     /**
    572      * This test just calls <code>writeReplace()</code> method<br>
    573      */
    574     @TestTargetNew(
    575         level = TestLevel.PARTIAL_COMPLETE,
    576         notes = "",
    577         method = "writeReplace",
    578         args = {}
    579     )
    580     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    581             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    582     public final void testWriteReplace2() {
    583         MyCertificate c1 = new MyFailingCertificate("TEST_TYPE", testEncoding);
    584 
    585         try {
    586             Object obj = c1.writeReplace();
    587         } catch (ObjectStreamException e) {
    588             //ok
    589         }
    590     }
    591 
    592     /**
    593      * @tests serialization/deserialization compatibility.
    594      */
    595     @TestTargets({
    596         @TestTargetNew(
    597             level = TestLevel.COMPLETE,
    598             notes = "Verifies serialization/deserialization compatibility. And tests default constructor",
    599             method = "!SerializationSelf",
    600             args = {}
    601         ),
    602         @TestTargetNew(
    603             level = TestLevel.PARTIAL_COMPLETE,
    604             notes = "",
    605             method = "writeReplace",
    606             args = {}
    607         ),
    608         @TestTargetNew(
    609             level = TestLevel.PARTIAL_COMPLETE,
    610             notes = "",
    611             method = "Certificate.CertificateRep.readResolve",
    612             args = {}
    613         )
    614     })
    615     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    616             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    617     public void testSerializationSelf() throws Exception {
    618         TestUtils.initCertPathSSCertChain();
    619 
    620         SerializationTest.verifySelf(TestUtils.rootCertificateSS);
    621     }
    622 
    623     /**
    624      * @tests serialization/deserialization compatibility with RI.
    625      */
    626     @TestTargets({
    627         @TestTargetNew(
    628             level = TestLevel.COMPLETE,
    629             notes = "Verifies serialization/deserialization compatibility.",
    630             method = "!SerializationGolden",
    631             args = {}
    632         ),
    633         @TestTargetNew(
    634             level = TestLevel.PARTIAL_COMPLETE,
    635             notes = "",
    636             method = "writeReplace",
    637             args = {}
    638         ),
    639         @TestTargetNew(
    640             level = TestLevel.PARTIAL_COMPLETE,
    641             notes = "",
    642             method = "Certificate.CertificateRep.readResolve",
    643             args = {}
    644         )
    645     })
    646     @AndroidOnly("Gets security providers with specific signature algorithm: " +
    647             "Security.getProviders(\"Signature.sha1WithRSAEncryption\")")
    648     public void testSerializationCompatibility() throws Exception {
    649         //create test file (once)
    650 //        SerializationTest.createGoldenFile("device/dalvik/libcore/security/src/test/resources/serialization", this, TestUtils.rootCertificateSS);
    651         TestUtils.initCertPathSSCertChain();
    652 
    653         SerializationTest.verifyGolden(this, TestUtils.rootCertificateSS);
    654     }
    655 }
    656