Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.keystore.cts;
     18 
     19 import android.security.keystore.KeyGenParameterSpec;
     20 import android.security.keystore.KeyInfo;
     21 import android.security.keystore.KeyProperties;
     22 import android.test.AndroidTestCase;
     23 import android.test.MoreAsserts;
     24 
     25 import android.keystore.cts.R;
     26 
     27 import java.io.InputStream;
     28 import java.security.InvalidKeyException;
     29 import java.security.KeyFactory;
     30 import java.security.KeyPair;
     31 import java.security.KeyPairGenerator;
     32 import java.security.NoSuchAlgorithmException;
     33 import java.security.NoSuchProviderException;
     34 import java.security.PrivateKey;
     35 import java.security.Provider;
     36 import java.security.Security;
     37 import java.security.interfaces.ECPublicKey;
     38 import java.security.interfaces.RSAPublicKey;
     39 import java.security.spec.ECPrivateKeySpec;
     40 import java.security.spec.ECPublicKeySpec;
     41 import java.security.spec.InvalidKeySpecException;
     42 import java.security.spec.KeySpec;
     43 import java.security.spec.PKCS8EncodedKeySpec;
     44 import java.security.spec.RSAPrivateKeySpec;
     45 import java.security.spec.RSAPublicKeySpec;
     46 import java.security.spec.X509EncodedKeySpec;
     47 import java.security.Provider.Service;
     48 import java.security.PublicKey;
     49 import java.util.ArrayList;
     50 import java.util.Arrays;
     51 import java.util.Date;
     52 import java.util.HashSet;
     53 import java.util.List;
     54 import java.util.Locale;
     55 import java.util.Set;
     56 
     57 import javax.crypto.SecretKey;
     58 import javax.crypto.spec.SecretKeySpec;
     59 
     60 public class KeyFactoryTest extends AndroidTestCase {
     61     private static final String EXPECTED_PROVIDER_NAME = TestUtils.EXPECTED_PROVIDER_NAME;
     62 
     63     private static final String[] EXPECTED_ALGORITHMS = {
     64         "EC",
     65         "RSA",
     66     };
     67 
     68     public void testAlgorithmList() {
     69         // Assert that Android Keystore Provider exposes exactly the expected KeyFactory algorithms.
     70         // We don't care whether the algorithms are exposed via aliases, as long as canonical names
     71         // of algorithms are accepted. If the Provider exposes extraneous algorithms, it'll be
     72         // caught because it'll have to expose at least one Service for such an algorithm, and this
     73         // Service's algorithm will not be in the expected set.
     74 
     75         Provider provider = Security.getProvider(EXPECTED_PROVIDER_NAME);
     76         Set<Service> services = provider.getServices();
     77         Set<String> actualAlgsLowerCase = new HashSet<String>();
     78         Set<String> expectedAlgsLowerCase = new HashSet<String>(
     79                 Arrays.asList(TestUtils.toLowerCase(EXPECTED_ALGORITHMS)));
     80         for (Service service : services) {
     81             if ("KeyFactory".equalsIgnoreCase(service.getType())) {
     82                 String algLowerCase = service.getAlgorithm().toLowerCase(Locale.US);
     83                 actualAlgsLowerCase.add(algLowerCase);
     84             }
     85         }
     86 
     87         TestUtils.assertContentsInAnyOrder(actualAlgsLowerCase,
     88                 expectedAlgsLowerCase.toArray(new String[0]));
     89     }
     90 
     91     public void testGetKeySpecWithKeystorePrivateKeyAndKeyInfoReflectsAllAuthorizations()
     92             throws Exception {
     93         Date keyValidityStart = new Date(System.currentTimeMillis() - TestUtils.DAY_IN_MILLIS);
     94         Date keyValidityForOriginationEnd =
     95                 new Date(System.currentTimeMillis() + TestUtils.DAY_IN_MILLIS);
     96         Date keyValidityForConsumptionEnd =
     97                 new Date(System.currentTimeMillis() + 3 * TestUtils.DAY_IN_MILLIS);
     98         for (String algorithm : EXPECTED_ALGORITHMS) {
     99             try {
    100                 String[] blockModes = new String[] {KeyProperties.BLOCK_MODE_ECB};
    101                 String[] encryptionPaddings =
    102                         new String[] {KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
    103                                 KeyProperties.ENCRYPTION_PADDING_RSA_OAEP};
    104                 String[] digests = new String[] {KeyProperties.DIGEST_SHA1,
    105                         KeyProperties.DIGEST_SHA224,
    106                         KeyProperties.DIGEST_SHA384,
    107                         KeyProperties.DIGEST_SHA512};
    108                 int purposes = KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_SIGN;
    109                 KeyPairGenerator keyGenerator =
    110                         KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
    111                 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", purposes)
    112                         .setBlockModes(blockModes)
    113                         .setEncryptionPaddings(encryptionPaddings)
    114                         .setDigests(digests)
    115                         .setKeyValidityStart(keyValidityStart)
    116                         .setKeyValidityForOriginationEnd(keyValidityForOriginationEnd)
    117                         .setKeyValidityForConsumptionEnd(keyValidityForConsumptionEnd)
    118                         .build());
    119                 KeyPair keyPair = keyGenerator.generateKeyPair();
    120                 KeyFactory keyFactory = getKeyFactory(algorithm);
    121                 KeyInfo keyInfo = keyFactory.getKeySpec(keyPair.getPrivate(), KeyInfo.class);
    122                 assertEquals("test1", keyInfo.getKeystoreAlias());
    123                 assertEquals(purposes, keyInfo.getPurposes());
    124                 TestUtils.assertContentsInAnyOrder(
    125                         Arrays.asList(keyInfo.getBlockModes()), blockModes);
    126 
    127                 List<String> actualEncryptionPaddings =
    128                         new ArrayList<String>(Arrays.asList(keyInfo.getEncryptionPaddings()));
    129                 // Keystore may have added ENCRYPTION_PADDING_NONE to allow software padding.
    130                 actualEncryptionPaddings.remove(KeyProperties.ENCRYPTION_PADDING_NONE);
    131                 TestUtils.assertContentsInAnyOrder(
    132                         actualEncryptionPaddings, encryptionPaddings);
    133 
    134                 List<String> actualDigests =
    135                         new ArrayList<String>(Arrays.asList(keyInfo.getDigests()));
    136                 // Keystore may have added DIGEST_NONE to allow software digesting.
    137                 actualDigests.remove(KeyProperties.DIGEST_NONE);
    138                 TestUtils.assertContentsInAnyOrder(actualDigests, digests);
    139 
    140                 MoreAsserts.assertEmpty(Arrays.asList(keyInfo.getSignaturePaddings()));
    141                 assertEquals(keyValidityStart, keyInfo.getKeyValidityStart());
    142                 assertEquals(keyValidityForOriginationEnd,
    143                         keyInfo.getKeyValidityForOriginationEnd());
    144                 assertEquals(keyValidityForConsumptionEnd,
    145                         keyInfo.getKeyValidityForConsumptionEnd());
    146                 assertFalse(keyInfo.isUserAuthenticationRequired());
    147                 assertFalse(keyInfo.isUserAuthenticationRequirementEnforcedBySecureHardware());
    148             } catch (Throwable e) {
    149                 throw new RuntimeException("Failed for " + algorithm, e);
    150             }
    151         }
    152     }
    153 
    154     public void testGetKeySpecWithKeystorePublicKeyRejectsKeyInfo()
    155             throws Exception {
    156         for (String algorithm : EXPECTED_ALGORITHMS) {
    157             try {
    158                 KeyPairGenerator keyGenerator =
    159                         KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
    160                 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build());
    161                 KeyPair keyPair = keyGenerator.generateKeyPair();
    162                 KeyFactory keyFactory = getKeyFactory(algorithm);
    163                 try {
    164                     keyFactory.getKeySpec(keyPair.getPublic(), KeyInfo.class);
    165                     fail();
    166                 } catch (InvalidKeySpecException expected) {}
    167             } catch (Throwable e) {
    168                 throw new RuntimeException("Failed for " + algorithm, e);
    169             }
    170         }
    171     }
    172 
    173     public void testGetKeySpecWithKeystorePrivateKeyRejectsTransparentKeySpecAndEncodedKeySpec()
    174             throws Exception {
    175         for (String algorithm : EXPECTED_ALGORITHMS) {
    176             try {
    177                 Class<? extends KeySpec> transparentKeySpecClass;
    178                 if ("EC".equalsIgnoreCase(algorithm)) {
    179                     transparentKeySpecClass = ECPrivateKeySpec.class;
    180                 } else if ("RSA".equalsIgnoreCase(algorithm)) {
    181                     transparentKeySpecClass = RSAPrivateKeySpec.class;
    182                 } else {
    183                     throw new RuntimeException("Unsupported key algorithm: " + algorithm);
    184                 }
    185 
    186                 KeyPairGenerator keyGenerator =
    187                         KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
    188                 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build());
    189                 KeyPair keyPair = keyGenerator.generateKeyPair();
    190 
    191                 KeyFactory keyFactory = getKeyFactory(algorithm);
    192                 try {
    193                     keyFactory.getKeySpec(keyPair.getPrivate(), transparentKeySpecClass);
    194                     fail();
    195                 } catch (InvalidKeySpecException expected) {}
    196 
    197                 try {
    198                     keyFactory.getKeySpec(keyPair.getPrivate(), PKCS8EncodedKeySpec.class);
    199                     fail();
    200                 } catch (InvalidKeySpecException expected) {}
    201             } catch (Throwable e) {
    202                 throw new RuntimeException("Failed for " + algorithm, e);
    203             }
    204         }
    205     }
    206 
    207     public void testGetKeySpecWithKeystorePublicKeyAcceptsX509EncodedKeySpec()
    208             throws Exception {
    209         for (String algorithm : EXPECTED_ALGORITHMS) {
    210             try {
    211                 KeyPairGenerator keyGenerator =
    212                         KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
    213                 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build());
    214                 KeyPair keyPair = keyGenerator.generateKeyPair();
    215                 PublicKey publicKey = keyPair.getPublic();
    216 
    217                 KeyFactory keyFactory = getKeyFactory(algorithm);
    218                 X509EncodedKeySpec x509EncodedSpec =
    219                         keyFactory.getKeySpec(publicKey, X509EncodedKeySpec.class);
    220                 MoreAsserts.assertEquals(publicKey.getEncoded(), x509EncodedSpec.getEncoded());
    221             } catch (Throwable e) {
    222                 throw new RuntimeException("Failed for " + algorithm, e);
    223             }
    224         }
    225     }
    226 
    227     public void testGetKeySpecWithKeystorePublicKeyAcceptsTransparentKeySpec()
    228             throws Exception {
    229         for (String algorithm : EXPECTED_ALGORITHMS) {
    230             try {
    231                 KeyPairGenerator keyGenerator =
    232                         KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
    233                 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build());
    234                 KeyPair keyPair = keyGenerator.generateKeyPair();
    235                 PublicKey publicKey = keyPair.getPublic();
    236 
    237                 KeyFactory keyFactory = getKeyFactory(algorithm);
    238                 if ("EC".equalsIgnoreCase(algorithm)) {
    239                     ECPublicKey ecPublicKey = (ECPublicKey) publicKey;
    240                     ECPublicKeySpec spec =
    241                             keyFactory.getKeySpec(publicKey, ECPublicKeySpec.class);
    242                     assertEquals(ecPublicKey.getW(), spec.getW());
    243                     TestUtils.assertECParameterSpecEqualsIgnoreSeedIfNotPresent(
    244                             ecPublicKey.getParams(), spec.getParams());
    245                 } else if ("RSA".equalsIgnoreCase(algorithm)) {
    246                     RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;
    247                     RSAPublicKeySpec spec =
    248                             keyFactory.getKeySpec(publicKey, RSAPublicKeySpec.class);
    249                     assertEquals(rsaPublicKey.getModulus(), spec.getModulus());
    250                     assertEquals(rsaPublicKey.getPublicExponent(), spec.getPublicExponent());
    251                 } else {
    252                     throw new RuntimeException("Unsupported key algorithm: " + algorithm);
    253                 }
    254             } catch (Throwable e) {
    255                 throw new RuntimeException("Failed for " + algorithm, e);
    256             }
    257         }
    258     }
    259 
    260     public void testTranslateKeyWithNullKeyThrowsInvalidKeyException() throws Exception {
    261         for (String algorithm : EXPECTED_ALGORITHMS) {
    262             try {
    263                 KeyFactory keyFactory = getKeyFactory(algorithm);
    264                 try {
    265                     keyFactory.translateKey(null);
    266                     fail();
    267                 } catch (InvalidKeyException expected) {}
    268             } catch (Throwable e) {
    269                 throw new RuntimeException("Failed for " + algorithm, e);
    270             }
    271         }
    272     }
    273 
    274     public void testTranslateKeyRejectsNonAndroidKeystoreKeys() throws Exception {
    275         for (String algorithm : EXPECTED_ALGORITHMS) {
    276             try {
    277                 SecretKey key = new SecretKeySpec(new byte[16], algorithm);
    278                 KeyFactory keyFactory = getKeyFactory(algorithm);
    279                 try {
    280                     keyFactory.translateKey(key);
    281                     fail();
    282                 } catch (InvalidKeyException expected) {}
    283             } catch (Throwable e) {
    284                 throw new RuntimeException("Failed for " + algorithm, e);
    285             }
    286         }
    287     }
    288 
    289     public void testTranslateKeyAcceptsAndroidKeystoreKeys() throws Exception {
    290         for (String algorithm : EXPECTED_ALGORITHMS) {
    291             try {
    292                 KeyPairGenerator keyGenerator =
    293                         KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
    294                 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build());
    295                 KeyPair keyPair = keyGenerator.generateKeyPair();
    296 
    297                 KeyFactory keyFactory = getKeyFactory(algorithm);
    298                 assertSame(keyPair.getPrivate(), keyFactory.translateKey(keyPair.getPrivate()));
    299                 assertSame(keyPair.getPublic(), keyFactory.translateKey(keyPair.getPublic()));
    300             } catch (Throwable e) {
    301                 throw new RuntimeException("Failed for " + algorithm, e);
    302             }
    303         }
    304     }
    305 
    306     public void testGeneratePrivateWithNullSpecThrowsInvalidKeySpecException() throws Exception {
    307         for (String algorithm : EXPECTED_ALGORITHMS) {
    308             try {
    309                 KeyFactory keyFactory = getKeyFactory(algorithm);
    310                 try {
    311                     keyFactory.generatePrivate(null);
    312                     fail();
    313                 } catch (InvalidKeySpecException expected) {}
    314             } catch (Throwable e) {
    315                 throw new RuntimeException("Failed for " + algorithm, e);
    316             }
    317         }
    318     }
    319 
    320     public void testGeneratePublicWithNullSpecThrowsInvalidKeySpecException() throws Exception {
    321         for (String algorithm : EXPECTED_ALGORITHMS) {
    322             try {
    323                 KeyFactory keyFactory = getKeyFactory(algorithm);
    324                 try {
    325                     keyFactory.generatePublic(null);
    326                     fail();
    327                 } catch (InvalidKeySpecException expected) {}
    328             } catch (Throwable e) {
    329                 throw new RuntimeException("Failed for " + algorithm, e);
    330             }
    331         }
    332     }
    333 
    334     public void testGeneratePrivateRejectsPKCS8EncodedKeySpec() throws Exception {
    335         for (String algorithm : EXPECTED_ALGORITHMS) {
    336             int resId;
    337             if ("EC".equalsIgnoreCase(algorithm)) {
    338                 resId = R.raw.ec_key1_pkcs8;
    339             } else if ("RSA".equalsIgnoreCase(algorithm)) {
    340                 resId = R.raw.rsa_key2_pkcs8;
    341             } else {
    342                 throw new RuntimeException("Unsupported key algorithm: " + algorithm);
    343             }
    344 
    345             byte[] pkcs8EncodedForm;
    346             try (InputStream in = getContext().getResources().openRawResource(resId)) {
    347                 pkcs8EncodedForm = TestUtils.drain(in);
    348             }
    349             PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(pkcs8EncodedForm);
    350             try {
    351                 KeyFactory keyFactory = getKeyFactory(algorithm);
    352                 try {
    353                     keyFactory.generatePrivate(spec);
    354                     fail();
    355                 } catch (InvalidKeySpecException expected) {}
    356             } catch (Throwable e) {
    357                 throw new RuntimeException("Failed for " + algorithm, e);
    358             }
    359         }
    360     }
    361 
    362     public void testGeneratePublicRejectsX509EncodedKeySpec() throws Exception {
    363         for (String algorithm : EXPECTED_ALGORITHMS) {
    364             int resId;
    365             if ("EC".equalsIgnoreCase(algorithm)) {
    366                 resId = R.raw.ec_key2_cert;
    367             } else if ("RSA".equalsIgnoreCase(algorithm)) {
    368                 resId = R.raw.rsa_key1_cert;
    369             } else {
    370                 throw new RuntimeException("Unsupported key algorithm: " + algorithm);
    371             }
    372 
    373             byte[] x509EncodedForm;
    374             try (InputStream in = getContext().getResources().openRawResource(resId)) {
    375                 x509EncodedForm = TestUtils.drain(in);
    376             }
    377             X509EncodedKeySpec spec = new X509EncodedKeySpec(x509EncodedForm);
    378             try {
    379                 KeyFactory keyFactory = getKeyFactory(algorithm);
    380                 try {
    381                     keyFactory.generatePublic(spec);
    382                     fail();
    383                 } catch (InvalidKeySpecException expected) {}
    384             } catch (Throwable e) {
    385                 throw new RuntimeException("Failed for " + algorithm, e);
    386             }
    387         }
    388     }
    389 
    390     public void testGeneratePrivateRejectsTransparentKeySpec() throws Exception {
    391         for (String algorithm : EXPECTED_ALGORITHMS) {
    392             int resId;
    393             Class<? extends KeySpec> keySpecClass;
    394             if ("EC".equalsIgnoreCase(algorithm)) {
    395                 resId = R.raw.ec_key2_pkcs8;
    396                 keySpecClass = ECPrivateKeySpec.class;
    397             } else if ("RSA".equalsIgnoreCase(algorithm)) {
    398                 resId = R.raw.rsa_key2_pkcs8;
    399                 keySpecClass = RSAPrivateKeySpec.class;
    400             } else {
    401                 throw new RuntimeException("Unsupported key algorithm: " + algorithm);
    402             }
    403             PrivateKey key = TestUtils.getRawResPrivateKey(getContext(), resId);
    404             KeyFactory anotherKeyFactory = KeyFactory.getInstance(algorithm);
    405             KeySpec spec = anotherKeyFactory.getKeySpec(key, keySpecClass);
    406 
    407             try {
    408                 KeyFactory keyFactory = getKeyFactory(algorithm);
    409                 try {
    410                     keyFactory.generatePrivate(spec);
    411                     fail();
    412                 } catch (InvalidKeySpecException expected) {}
    413             } catch (Throwable e) {
    414                 throw new RuntimeException("Failed for " + algorithm, e);
    415             }
    416         }
    417     }
    418 
    419     public void testGeneratePublicRejectsTransparentKeySpec() throws Exception {
    420         for (String algorithm : EXPECTED_ALGORITHMS) {
    421             int resId;
    422             Class<? extends KeySpec> keySpecClass;
    423             if ("EC".equalsIgnoreCase(algorithm)) {
    424                 resId = R.raw.ec_key2_cert;
    425                 keySpecClass = ECPublicKeySpec.class;
    426             } else if ("RSA".equalsIgnoreCase(algorithm)) {
    427                 resId = R.raw.rsa_key2_cert;
    428                 keySpecClass = RSAPublicKeySpec.class;
    429             } else {
    430                 throw new RuntimeException("Unsupported key algorithm: " + algorithm);
    431             }
    432             PublicKey key = TestUtils.getRawResX509Certificate(getContext(), resId).getPublicKey();
    433             KeyFactory anotherKeyFactory = KeyFactory.getInstance(algorithm);
    434             KeySpec spec = anotherKeyFactory.getKeySpec(key, keySpecClass);
    435 
    436             try {
    437                 KeyFactory keyFactory = getKeyFactory(algorithm);
    438                 try {
    439                     keyFactory.generatePublic(spec);
    440                     fail();
    441                 } catch (InvalidKeySpecException expected) {}
    442             } catch (Throwable e) {
    443                 throw new RuntimeException("Failed for " + algorithm, e);
    444             }
    445         }
    446     }
    447 
    448     public void testGeneratePrivateAndPublicRejectKeyInfo() throws Exception {
    449         for (String algorithm : EXPECTED_ALGORITHMS) {
    450             try {
    451                 KeyPairGenerator keyGenerator =
    452                         KeyPairGenerator.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
    453                 keyGenerator.initialize(new KeyGenParameterSpec.Builder("test1", 0).build());
    454                 KeyPair keyPair = keyGenerator.generateKeyPair();
    455                 KeyInfo keyInfo = TestUtils.getKeyInfo(keyPair.getPrivate());
    456 
    457                 KeyFactory keyFactory = getKeyFactory(algorithm);
    458                 try {
    459                     keyFactory.generatePrivate(keyInfo);
    460                     fail();
    461                 } catch (InvalidKeySpecException expected) {}
    462 
    463                 try {
    464                     keyFactory.generatePublic(keyInfo);
    465                     fail();
    466                 } catch (InvalidKeySpecException expected) {}
    467             } catch (Throwable e) {
    468                 throw new RuntimeException("Failed for " + algorithm, e);
    469             }
    470         }
    471     }
    472 
    473     private KeyFactory getKeyFactory(String algorithm) throws NoSuchAlgorithmException,
    474             NoSuchProviderException {
    475         return KeyFactory.getInstance(algorithm, EXPECTED_PROVIDER_NAME);
    476     }
    477 }
    478