diff options
| author | 2017-07-03 15:07:20 +0000 | |
|---|---|---|
| committer | 2017-07-03 15:07:20 +0000 | |
| commit | b2b73e4956fa2ffebc80893b68f37989a631eca1 (patch) | |
| tree | 2dc38dd048f1e2a224330a209bd640f743b91f9f | |
| parent | 19dc697f33c2cfb72ce1e8fcee51f5d4e7ed1c74 (diff) | |
| parent | c20c2ea28ea755a40263545c34adffe72f675a60 (diff) | |
Merge changes from topic 'revert-update-conscrypt' into oc-dr1-dev
* changes:
Revert "Track updates to Conscrypt". DO NOT MERGE ANYWHERE.
Revert "Delete obsolete and unused KeyStoreTests". DO NOT MERGE ANYWHERE.
8 files changed, 3904 insertions, 2 deletions
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index 0b1569ca4ff5..b56437eba167 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -20,7 +20,6 @@ import android.os.SystemProperties; import android.util.Log; import com.android.internal.os.RoSystemProperties; -import com.android.org.conscrypt.Conscrypt; import com.android.org.conscrypt.OpenSSLContextImpl; import com.android.org.conscrypt.OpenSSLSocketImpl; import com.android.org.conscrypt.SSLClientSessionCache; @@ -213,7 +212,7 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { private SSLSocketFactory makeSocketFactory( KeyManager[] keyManagers, TrustManager[] trustManagers) { try { - OpenSSLContextImpl sslContext = (OpenSSLContextImpl) Conscrypt.newPreferredSSLContextSpi(); + OpenSSLContextImpl sslContext = OpenSSLContextImpl.getPreferred(); sslContext.engineInit(keyManagers, trustManagers, null); sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache); return sslContext.engineGetSocketFactory(); diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk new file mode 100644 index 000000000000..a740b1342690 --- /dev/null +++ b/keystore/tests/Android.mk @@ -0,0 +1,16 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +# We only want this apk build for tests. +LOCAL_MODULE_TAGS := tests +LOCAL_CERTIFICATE := platform + +LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt +LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test + +# Include all test java files. +LOCAL_SRC_FILES := $(call all-java-files-under, src) + +LOCAL_PACKAGE_NAME := KeyStoreTests + +include $(BUILD_PACKAGE) diff --git a/keystore/tests/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml new file mode 100644 index 000000000000..415442f85acb --- /dev/null +++ b/keystore/tests/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.security.tests" + android:sharedUserId="android.uid.system"> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="android.security.tests" + android:label="KeyStore Tests"> + </instrumentation> +</manifest> diff --git a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java new file mode 100644 index 000000000000..bc8dd13e99f3 --- /dev/null +++ b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java @@ -0,0 +1,152 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +import android.test.AndroidTestCase; + +import java.math.BigInteger; +import java.util.Date; + +import javax.security.auth.x500.X500Principal; + +public class KeyPairGeneratorSpecTest extends AndroidTestCase { + private static final String TEST_ALIAS_1 = "test1"; + + private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1"); + + private static final long NOW_MILLIS = System.currentTimeMillis(); + + private static final BigInteger SERIAL_1 = BigInteger.ONE; + + /* We have to round this off because X509v3 doesn't store milliseconds. */ + private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L)); + + @SuppressWarnings("deprecation") + private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1); + + public void testConstructor_Success() throws Exception { + KeyPairGeneratorSpec spec = + new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, + SERIAL_1, NOW, NOW_PLUS_10_YEARS, 0); + + assertEquals("Context should be the one specified", getContext(), spec.getContext()); + + assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias()); + + assertEquals("Key algorithm should be the one specified", "RSA", spec.getKeyType()); + + assertEquals("Key size should be the one specified", 1024, spec.getKeySize()); + + assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN()); + + assertEquals("startDate should be the one specified", NOW, spec.getStartDate()); + + assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate()); + } + + public void testBuilder_Success() throws Exception { + KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setKeyType("RSA") + .setKeySize(1024) + .setSubject(TEST_DN_1) + .setSerialNumber(SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .setEncryptionRequired() + .build(); + + assertEquals("Context should be the one specified", getContext(), spec.getContext()); + + assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias()); + + assertEquals("Key algorithm should be the one specified", "RSA", spec.getKeyType()); + + assertEquals("Key size should be the one specified", 1024, spec.getKeySize()); + + assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN()); + + assertEquals("startDate should be the one specified", NOW, spec.getStartDate()); + + assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate()); + + assertEquals("encryption flag should be on", KeyStore.FLAG_ENCRYPTED, spec.getFlags()); + } + + public void testConstructor_NullContext_Failure() throws Exception { + try { + new KeyPairGeneratorSpec(null, TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW, + NOW_PLUS_10_YEARS, 0); + fail("Should throw IllegalArgumentException when context is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullKeystoreAlias_Failure() throws Exception { + try { + new KeyPairGeneratorSpec(getContext(), null, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW, + NOW_PLUS_10_YEARS, 0); + fail("Should throw IllegalArgumentException when keystoreAlias is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullSubjectDN_Failure() throws Exception { + try { + new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW, + NOW_PLUS_10_YEARS, 0); + fail("Should throw IllegalArgumentException when subjectDN is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullSerial_Failure() throws Exception { + try { + new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW, + NOW_PLUS_10_YEARS, 0); + fail("Should throw IllegalArgumentException when startDate is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullStartDate_Failure() throws Exception { + try { + new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, + null, NOW_PLUS_10_YEARS, 0); + fail("Should throw IllegalArgumentException when startDate is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_NullEndDate_Failure() throws Exception { + try { + new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, + NOW, null, 0); + fail("Should throw IllegalArgumentException when keystoreAlias is null"); + } catch (IllegalArgumentException success) { + } + } + + public void testConstructor_EndBeforeStart_Failure() throws Exception { + try { + new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, + NOW_PLUS_10_YEARS, NOW, 0); + fail("Should throw IllegalArgumentException when end is before start"); + } catch (IllegalArgumentException success) { + } + } +} diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java new file mode 100644 index 000000000000..319cf32397a1 --- /dev/null +++ b/keystore/tests/src/android/security/KeyStoreTest.java @@ -0,0 +1,974 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +import android.app.Activity; +import android.os.Binder; +import android.os.IBinder; +import android.os.Process; +import android.security.keymaster.ExportResult; +import android.security.keymaster.KeyCharacteristics; +import android.security.keymaster.KeymasterArguments; +import android.security.keymaster.KeymasterBlob; +import android.security.keymaster.KeymasterDefs; +import android.security.keymaster.OperationResult; +import android.test.ActivityUnitTestCase; +import android.test.AssertionFailedError; +import android.test.MoreAsserts; +import android.test.suitebuilder.annotation.MediumTest; +import com.android.org.conscrypt.NativeConstants; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.HashSet; +import java.security.spec.RSAKeyGenParameterSpec; + +/** + * Junit / Instrumentation test case for KeyStore class + * + * Running the test suite: + * + * runtest keystore-unit + * + * Or this individual test case: + * + * runtest --path frameworks/base/keystore/tests/src/android/security/KeyStoreTest.java + */ +@MediumTest +public class KeyStoreTest extends ActivityUnitTestCase<Activity> { + private static final String TEST_PASSWD = "12345678"; + private static final String TEST_PASSWD2 = "87654321"; + private static final String TEST_KEYNAME = "test-key"; + private static final String TEST_KEYNAME1 = "test-key.1"; + private static final String TEST_KEYNAME2 = "test-key\02"; + private static final byte[] TEST_KEYVALUE = "test value".getBytes(StandardCharsets.UTF_8); + + // "Hello, World" in Chinese + private static final String TEST_I18N_KEY = "\u4F60\u597D, \u4E16\u754C"; + private static final byte[] TEST_I18N_VALUE = TEST_I18N_KEY.getBytes(StandardCharsets.UTF_8); + + // Test vector data for signatures + private static final int RSA_KEY_SIZE = 1024; + private static final byte[] TEST_DATA = new byte[RSA_KEY_SIZE / 8]; + static { + for (int i = 0; i < TEST_DATA.length; i++) { + TEST_DATA[i] = (byte) i; + } + } + + private KeyStore mKeyStore = null; + + public KeyStoreTest() { + super(Activity.class); + } + + private static final byte[] PRIVKEY_BYTES = hexToBytes( + "308204BE020100300D06092A864886F70D0101010500048204A8308204A4020100028201" + + "0100E0473E8AB8F2284FEB9E742FF9748FA118ED98633C92F52AEB7A2EBE0D3BE60329BE" + + "766AD10EB6A515D0D2CFD9BEA7930F0C306537899F7958CD3E85B01F8818524D312584A9" + + "4B251E3625B54141EDBFEE198808E1BB97FC7CB49B9EAAAF68E9C98D7D0EDC53BBC0FA00" + + "34356D6305FBBCC3C7001405386ABBC873CB0F3EF7425F3D33DF7B315AE036D2A0B66AFD" + + "47503B169BF36E3B5162515B715FDA83DEAF2C58AEB9ABFB3097C3CC9DD9DBE5EF296C17" + + "6139028E8A671E63056D45F40188D2C4133490845DE52C2534E9C6B2478C07BDAE928823" + + "B62D066C7770F9F63F3DBA247F530844747BE7AAA85D853B8BD244ACEC3DE3C89AB46453" + + "AB4D24C3AC6902030100010282010037784776A5F17698F5AC960DFB83A1B67564E648BD" + + "0597CF8AB8087186F2669C27A9ECBDD480F0197A80D07309E6C6A96F925331E57F8B4AC6" + + "F4D45EDA45A23269C09FC428C07A4E6EDF738A15DEC97FABD2F2BB47A14F20EA72FCFE4C" + + "36E01ADA77BD137CD8D4DA10BB162E94A4662971F175F985FA188F056CB97EE2816F43AB" + + "9D3747612486CDA8C16196C30818A995EC85D38467791267B3BF21F273710A6925862576" + + "841C5B6712C12D4BD20A2F3299ADB7C135DA5E9515ABDA76E7CAF2A3BE80551D073B78BF" + + "1162C48AD2B7F4743A0238EE4D252F7D5E7E6533CCAE64CCB39360075A2FD1E034EC3AE5" + + "CE9C408CCBF0E25E4114021687B3DD4754AE8102818100F541884BC3737B2922D4119EF4" + + "5E2DEE2CD4CBB75F45505A157AA5009F99C73A2DF0724AC46024306332EA898177634546" + + "5DC6DF1E0A6F140AFF3B7396E6A8994AC5DAA96873472FE37749D14EB3E075E629DBEB35" + + "83338A6F3649D0A2654A7A42FD9AB6BFA4AC4D481D390BB229B064BDC311CC1BE1B63189" + + "DA7C40CDECF2B102818100EA1A742DDB881CEDB7288C87E38D868DD7A409D15A43F445D5" + + "377A0B5731DDBFCA2DAF28A8E13CD5C0AFCEC3347D74A39E235A3CD9633F274DE2B94F92" + + "DF43833911D9E9F1CF58F27DE2E08FF45964C720D3EC2139DC7CAFC912953CDECB2F355A" + + "2E2C35A50FAD754CB3B23166424BA3B6E3112A2B898C38C5C15EDB238693390281805182" + + "8F1EC6FD996029901BAF1D7E337BA5F0AF27E984EAD895ACE62BD7DF4EE45A224089F2CC" + + "151AF3CD173FCE0474BCB04F386A2CDCC0E0036BA2419F54579262D47100BE931984A3EF" + + "A05BECF141574DC079B3A95C4A83E6C43F3214D6DF32D512DE198085E531E616B83FD7DD" + + "9D1F4E2607C3333D07C55D107D1D3893587102818100DB4FB50F50DE8EDB53FF34C80931" + + "88A0512867DA2CCA04897759E587C244010DAF8664D59E8083D16C164789301F67A9F078" + + "060D834A2ADBD367575B68A8A842C2B02A89B3F31FCCEC8A22FE395795C5C6C7422B4E5D" + + "74A1E9A8F30E7759B9FC2D639C1F15673E84E93A5EF1506F4315383C38D45CBD1B14048F" + + "4721DC82326102818100D8114593AF415FB612DBF1923710D54D07486205A76A3B431949" + + "68C0DFF1F11EF0F61A4A337D5FD3741BBC9640E447B8B6B6C47C3AC1204357D3B0C55BA9" + + "286BDA73F629296F5FA9146D8976357D3C751E75148696A40B74685C82CE30902D639D72" + + "4FF24D5E2E9407EE34EDED2E3B4DF65AA9BCFEB6DF28D07BA6903F165768"); + + private static final byte[] AES256_BYTES = hexToBytes( + "0CC175B9C0F1B6A831C399E269772661CEC520EA51EA0A47E87295FA3245A605"); + + private static byte[] hexToBytes(String s) { + int len = s.length(); + byte[] data = new byte[len / 2]; + for (int i = 0; i < len; i += 2) { + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit( + s.charAt(i + 1), 16)); + } + return data; + } + + @Override + protected void setUp() throws Exception { + mKeyStore = KeyStore.getInstance(); + if (mKeyStore.state() != KeyStore.State.UNINITIALIZED) { + mKeyStore.reset(); + } + assertEquals("KeyStore should be in an uninitialized state", + KeyStore.State.UNINITIALIZED, mKeyStore.state()); + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + mKeyStore.reset(); + super.tearDown(); + } + + public void testState() throws Exception { + assertEquals(KeyStore.State.UNINITIALIZED, mKeyStore.state()); + } + + public void testPassword() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + assertEquals(KeyStore.State.UNLOCKED, mKeyStore.state()); + } + + public void testGet() throws Exception { + assertNull(mKeyStore.get(TEST_KEYNAME)); + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertNull(mKeyStore.get(TEST_KEYNAME)); + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME))); + } + + public void testPut() throws Exception { + assertNull(mKeyStore.get(TEST_KEYNAME)); + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, + KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME))); + } + + public void testPut_grantedUid_Wifi() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID, + KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testPut_ungrantedUid_Bluetooth() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID, + KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID, + KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + } + + public void testI18n() throws Exception { + assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE, KeyStore.UID_SELF, + KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_I18N_KEY)); + mKeyStore.onUserPasswordChanged(TEST_I18N_KEY); + assertTrue(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE, KeyStore.UID_SELF, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(mKeyStore.contains(TEST_I18N_KEY)); + } + + public void testDelete() throws Exception { + assertFalse(mKeyStore.delete(TEST_KEYNAME)); + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertFalse(mKeyStore.delete(TEST_KEYNAME)); + + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME))); + assertTrue(mKeyStore.delete(TEST_KEYNAME)); + assertNull(mKeyStore.get(TEST_KEYNAME)); + } + + public void testDelete_grantedUid_Wifi() throws Exception { + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID)); + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID)); + + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertTrue(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testDelete_ungrantedUid_Bluetooth() throws Exception { + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID)); + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID)); + + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID, + KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + } + + public void testContains() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + } + + public void testContains_grantedUid_Wifi() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testContains_grantedUid_Bluetooth() throws Exception { + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + + assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID, + KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + } + + public void testList() throws Exception { + String[] emptyResult = mKeyStore.list(TEST_KEYNAME); + assertNotNull(emptyResult); + assertEquals(0, emptyResult.length); + + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED); + mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED); + + String[] results = mKeyStore.list(TEST_KEYNAME); + assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()), + TEST_KEYNAME2.substring(TEST_KEYNAME.length()))), + new HashSet(Arrays.asList(results))); + } + + public void testList_ungrantedUid_Bluetooth() throws Exception { + String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.BLUETOOTH_UID); + assertEquals(0, results1.length); + + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED); + mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED); + + String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.BLUETOOTH_UID); + assertEquals(0, results2.length); + } + + public void testList_grantedUid_Wifi() throws Exception { + String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.WIFI_UID); + assertNotNull(results1); + assertEquals(0, results1.length); + + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED); + mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED); + + String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.WIFI_UID); + assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()), + TEST_KEYNAME2.substring(TEST_KEYNAME.length()))), + new HashSet(Arrays.asList(results2))); + } + + public void testList_grantedUid_Vpn() throws Exception { + String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.VPN_UID); + assertNotNull(results1); + assertEquals(0, results1.length); + + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED); + mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED); + + String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.VPN_UID); + assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()), + TEST_KEYNAME2.substring(TEST_KEYNAME.length()))), + new HashSet(Arrays.asList(results2))); + } + + public void testLock() throws Exception { + assertFalse(mKeyStore.lock()); + + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertEquals(KeyStore.State.UNLOCKED, mKeyStore.state()); + + assertTrue(mKeyStore.lock()); + assertEquals(KeyStore.State.LOCKED, mKeyStore.state()); + } + + public void testUnlock() throws Exception { + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertEquals(KeyStore.State.UNLOCKED, mKeyStore.state()); + mKeyStore.lock(); + + assertFalse(mKeyStore.unlock(TEST_PASSWD2)); + assertTrue(mKeyStore.unlock(TEST_PASSWD)); + } + + public void testIsEmpty() throws Exception { + assertTrue(mKeyStore.isEmpty()); + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + assertTrue(mKeyStore.isEmpty()); + mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED); + assertFalse(mKeyStore.isEmpty()); + mKeyStore.reset(); + assertTrue(mKeyStore.isEmpty()); + } + + public void testGenerate_NotInitialized_Fail() throws Exception { + assertFalse("Should fail when keystore is not initialized", + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + } + + public void testGenerate_Locked_Fail() throws Exception { + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + mKeyStore.lock(); + assertFalse("Should fail when keystore is locked", + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + } + + public void testGenerate_Success() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to generate key when unlocked", + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testGenerate_grantedUid_Wifi_Success() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to generate key when unlocked", + mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + } + + public void testGenerate_ungrantedUid_Bluetooth_Failure() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID, + NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + } + + public void testImport_Success() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME, + PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testImport_grantedUid_Wifi_Success() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME, + PRIVKEY_BYTES, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + } + + public void testImport_ungrantedUid_Bluetooth_Failure() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID, + KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + } + + public void testImport_Failure_BadEncoding() throws Exception { + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + + assertFalse("Invalid DER-encoded key should not be imported", mKeyStore.importKey( + TEST_KEYNAME, TEST_DATA, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + } + + public void testSign_Success() throws Exception { + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + + assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA); + + assertNotNull("Signature should not be null", signature); + } + + public void testVerify_Success() throws Exception { + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + + assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA); + + assertNotNull("Signature should not be null", signature); + + assertTrue("Signature should verify with same data", + mKeyStore.verify(TEST_KEYNAME, TEST_DATA, signature)); + } + + public void testSign_NotInitialized_Failure() throws Exception { + assertNull("Should not be able to sign without first initializing the keystore", + mKeyStore.sign(TEST_KEYNAME, TEST_DATA)); + } + + public void testSign_NotGenerated_Failure() throws Exception { + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + + assertNull("Should not be able to sign without first generating keys", + mKeyStore.sign(TEST_KEYNAME, TEST_DATA)); + } + + public void testGrant_Generated_Success() throws Exception { + assertTrue("Password should work for keystore", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to generate key for testcase", + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + + assertTrue("Should be able to grant key to other user", + mKeyStore.grant(TEST_KEYNAME, 0)); + } + + public void testGrant_Imported_Success() throws Exception { + assertTrue("Password should work for keystore", mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to import key for testcase", mKeyStore.importKey(TEST_KEYNAME, + PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertTrue("Should be able to grant key to other user", mKeyStore.grant(TEST_KEYNAME, 0)); + } + + public void testGrant_NoKey_Failure() throws Exception { + assertTrue("Should be able to unlock keystore for test", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertFalse("Should not be able to grant without first initializing the keystore", + mKeyStore.grant(TEST_KEYNAME, 0)); + } + + public void testGrant_NotInitialized_Failure() throws Exception { + assertFalse("Should not be able to grant without first initializing the keystore", + mKeyStore.grant(TEST_KEYNAME, 0)); + } + + public void testUngrant_Generated_Success() throws Exception { + assertTrue("Password should work for keystore", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to generate key for testcase", + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + + assertTrue("Should be able to grant key to other user", + mKeyStore.grant(TEST_KEYNAME, 0)); + + assertTrue("Should be able to ungrant key to other user", + mKeyStore.ungrant(TEST_KEYNAME, 0)); + } + + public void testUngrant_Imported_Success() throws Exception { + assertTrue("Password should work for keystore", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to import key for testcase", mKeyStore.importKey(TEST_KEYNAME, + PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertTrue("Should be able to grant key to other user", + mKeyStore.grant(TEST_KEYNAME, 0)); + + assertTrue("Should be able to ungrant key to other user", + mKeyStore.ungrant(TEST_KEYNAME, 0)); + } + + public void testUngrant_NotInitialized_Failure() throws Exception { + assertFalse("Should fail to ungrant key when keystore not initialized", + mKeyStore.ungrant(TEST_KEYNAME, 0)); + } + + public void testUngrant_NoGrant_Failure() throws Exception { + assertTrue("Password should work for keystore", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to generate key for testcase", + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + + assertFalse("Should not be able to revoke not existent grant", + mKeyStore.ungrant(TEST_KEYNAME, 0)); + } + + public void testUngrant_DoubleUngrant_Failure() throws Exception { + assertTrue("Password should work for keystore", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to generate key for testcase", + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + + assertTrue("Should be able to grant key to other user", + mKeyStore.grant(TEST_KEYNAME, 0)); + + assertTrue("Should be able to ungrant key to other user", + mKeyStore.ungrant(TEST_KEYNAME, 0)); + + assertFalse("Should fail to ungrant key to other user second time", + mKeyStore.ungrant(TEST_KEYNAME, 0)); + } + + public void testUngrant_DoubleGrantUngrant_Failure() throws Exception { + assertTrue("Password should work for keystore", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to generate key for testcase", + mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + + assertTrue("Should be able to grant key to other user", + mKeyStore.grant(TEST_KEYNAME, 0)); + + assertTrue("Should be able to grant key to other user a second time", + mKeyStore.grant(TEST_KEYNAME, 0)); + + assertTrue("Should be able to ungrant key to other user", + mKeyStore.ungrant(TEST_KEYNAME, 0)); + + assertFalse("Should fail to ungrant key to other user second time", + mKeyStore.ungrant(TEST_KEYNAME, 0)); + } + + public void testDuplicate_grantedUid_Wifi_Success() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + + assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + + // source doesn't exist + assertFalse(mKeyStore.duplicate(TEST_KEYNAME1, -1, TEST_KEYNAME1, Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID)); + + // Copy from current UID to granted UID + assertTrue(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME1, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME1)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID)); + assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME1, Process.WIFI_UID)); + + // Copy from granted UID to same granted UID + assertTrue(mKeyStore.duplicate(TEST_KEYNAME1, Process.WIFI_UID, TEST_KEYNAME2, + Process.WIFI_UID)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID)); + assertTrue(mKeyStore.contains(TEST_KEYNAME2, Process.WIFI_UID)); + assertFalse(mKeyStore.duplicate(TEST_KEYNAME1, Process.WIFI_UID, TEST_KEYNAME2, + Process.WIFI_UID)); + + assertTrue(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, -1)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME1)); + assertTrue(mKeyStore.contains(TEST_KEYNAME2)); + assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, -1)); + } + + public void testDuplicate_ungrantedUid_Bluetooth_Failure() throws Exception { + assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + + assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, + RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null)); + + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + + assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, Process.BLUETOOTH_UID)); + assertFalse(mKeyStore.duplicate(TEST_KEYNAME, Process.BLUETOOTH_UID, TEST_KEYNAME2, + Process.BLUETOOTH_UID)); + + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID)); + } + + /** + * The amount of time to allow before and after expected time for variance + * in timing tests. + */ + private static final long SLOP_TIME_MILLIS = 15000L; + + public void testGetmtime_Success() throws Exception { + assertTrue("Password should work for keystore", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME, + PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + long now = System.currentTimeMillis(); + long actual = mKeyStore.getmtime(TEST_KEYNAME); + + long expectedAfter = now - SLOP_TIME_MILLIS; + long expectedBefore = now + SLOP_TIME_MILLIS; + + assertLessThan("Time should be close to current time", expectedBefore, actual); + assertGreaterThan("Time should be close to current time", expectedAfter, actual); + } + + private static void assertLessThan(String explanation, long expectedBefore, long actual) { + if (actual >= expectedBefore) { + throw new AssertionFailedError(explanation + ": actual=" + actual + + ", expected before: " + expectedBefore); + } + } + + private static void assertGreaterThan(String explanation, long expectedAfter, long actual) { + if (actual <= expectedAfter) { + throw new AssertionFailedError(explanation + ": actual=" + actual + + ", expected after: " + expectedAfter); + } + } + + public void testGetmtime_NonExist_Failure() throws Exception { + assertTrue("Password should work for keystore", + mKeyStore.onUserPasswordChanged(TEST_PASSWD)); + + assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME, + PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertEquals("-1 should be returned for non-existent key", + -1L, mKeyStore.getmtime(TEST_KEYNAME2)); + } + + private KeyCharacteristics generateRsaKey(String name) throws Exception { + KeymasterArguments args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); + args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048); + args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4); + + KeyCharacteristics outCharacteristics = new KeyCharacteristics(); + int result = mKeyStore.generateKey(name, args, null, 0, outCharacteristics); + assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result); + return outCharacteristics; + } + + public void testGenerateKey() throws Exception { + generateRsaKey("test"); + mKeyStore.delete("test"); + } + + public void testGenerateRsaWithEntropy() throws Exception { + byte[] entropy = new byte[] {1,2,3,4,5}; + String name = "test"; + KeymasterArguments args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); + args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048); + args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4); + + KeyCharacteristics outCharacteristics = new KeyCharacteristics(); + int result = mKeyStore.generateKey(name, args, entropy, 0, outCharacteristics); + assertEquals("generateKey should succeed", KeyStore.NO_ERROR, result); + } + + public void testGenerateAndDelete() throws Exception { + generateRsaKey("test"); + assertTrue("delete should succeed", mKeyStore.delete("test")); + } + + public void testGetKeyCharacteristicsSuccess() throws Exception { + mKeyStore.onUserPasswordChanged(TEST_PASSWD); + String name = "test"; + KeyCharacteristics gen = generateRsaKey(name); + KeyCharacteristics call = new KeyCharacteristics(); + int result = mKeyStore.getKeyCharacteristics(name, null, null, call); + assertEquals("getKeyCharacteristics should succeed", KeyStore.NO_ERROR, result); + mKeyStore.delete("test"); + } + + public void testAppId() throws Exception { + String name = "test"; + byte[] id = new byte[] {0x01, 0x02, 0x03}; + KeymasterArguments args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048); + args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB); + args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); + args.addBytes(KeymasterDefs.KM_TAG_APPLICATION_ID, id); + args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4); + + KeyCharacteristics outCharacteristics = new KeyCharacteristics(); + int result = mKeyStore.generateKey(name, args, null, 0, outCharacteristics); + assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result); + assertEquals("getKeyCharacteristics should fail without application ID", + KeymasterDefs.KM_ERROR_INVALID_KEY_BLOB, + mKeyStore.getKeyCharacteristics(name, null, null, outCharacteristics)); + assertEquals("getKeyCharacteristics should succeed with application ID", + KeyStore.NO_ERROR, + mKeyStore.getKeyCharacteristics(name, new KeymasterBlob(id), null, + outCharacteristics)); + } + + + public void testExportRsa() throws Exception { + String name = "test"; + generateRsaKey(name); + ExportResult result = mKeyStore.exportKey(name, KeymasterDefs.KM_KEY_FORMAT_X509, null, + null); + assertEquals("Export success", KeyStore.NO_ERROR, result.resultCode); + // TODO: Verify we have an RSA public key that's well formed. + } + + public void testAesGcmEncryptSuccess() throws Exception { + String name = "test"; + KeymasterArguments args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256); + args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM); + args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); + + KeyCharacteristics outCharacteristics = new KeyCharacteristics(); + int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics); + assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc); + + args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); + args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + args.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 128); + OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, + true, args, null); + IBinder token = result.token; + assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode); + result = mKeyStore.update(token, null, new byte[] {0x01, 0x02, 0x03, 0x04}); + assertEquals("Update should succeed", KeyStore.NO_ERROR, result.resultCode); + assertEquals("Finish should succeed", KeyStore.NO_ERROR, + mKeyStore.finish(token, null, null).resultCode); + // TODO: Assert that an AEAD tag was returned by finish + } + + public void testBadToken() throws Exception { + IBinder token = new Binder(); + OperationResult result = mKeyStore.update(token, null, new byte[] {0x01}); + assertEquals("Update with invalid token should fail", + KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, result.resultCode); + } + + private int importAesKey(String name, byte[] key, int size, int mode) { + KeymasterArguments args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mode); + args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, size); + args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); + return mKeyStore.importKey(name, args, KeymasterDefs.KM_KEY_FORMAT_RAW, key, 0, + new KeyCharacteristics()); + } + private byte[] doOperation(String name, int purpose, byte[] in, KeymasterArguments beginArgs) { + OperationResult result = mKeyStore.begin(name, purpose, + true, beginArgs, null); + assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode); + IBinder token = result.token; + result = mKeyStore.update(token, null, in); + assertEquals("Update should succeed", KeyStore.NO_ERROR, result.resultCode); + assertEquals("All data should be consumed", in.length, result.inputConsumed); + assertEquals("Finish should succeed", KeyStore.NO_ERROR, + mKeyStore.finish(token, null, null).resultCode); + return result.output; + } + + public void testImportAes() throws Exception { + int result = importAesKey("aes", AES256_BYTES, 256, KeymasterDefs.KM_MODE_ECB); + assertEquals("import should succeed", KeyStore.NO_ERROR, result); + mKeyStore.delete("aes"); + } + + public void testAes256Ecb() throws Exception { + byte[] key = + hexToBytes("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); + String name = "aes"; + assertEquals(KeyStore.NO_ERROR, importAesKey(name, key, 256, KeymasterDefs.KM_MODE_ECB)); + byte[][] testVectors = new byte[][] { + hexToBytes("6bc1bee22e409f96e93d7e117393172a"), + hexToBytes("ae2d8a571e03ac9c9eb76fac45af8e51"), + hexToBytes("30c81c46a35ce411e5fbc1191a0a52ef"), + hexToBytes("f69f2445df4f9b17ad2b417be66c3710")}; + byte[][] cipherVectors = new byte[][] { + hexToBytes("f3eed1bdb5d2a03c064b5a7e3db181f8"), + hexToBytes("591ccb10d410ed26dc5ba74a31362870"), + hexToBytes("b6ed21b99ca6f4f9f153e7b1beafed1d"), + hexToBytes("23304b7a39f9f3ff067d8d8f9e24ecc7")}; + KeymasterArguments beginArgs = new KeymasterArguments(); + beginArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); + beginArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB); + beginArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + for (int i = 0; i < testVectors.length; i++) { + byte[] cipherText = doOperation(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, testVectors[i], + beginArgs); + MoreAsserts.assertEquals(cipherVectors[i], cipherText); + } + for (int i = 0; i < testVectors.length; i++) { + byte[] plainText = doOperation(name, KeymasterDefs.KM_PURPOSE_DECRYPT, + cipherVectors[i], beginArgs); + MoreAsserts.assertEquals(testVectors[i], plainText); + } + } + + // This is a very implementation specific test and should be thrown out eventually, however it + // is nice for now to test that keystore is properly pruning operations. + public void testOperationPruning() throws Exception { + String name = "test"; + KeymasterArguments args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256); + args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR); + args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); + + KeyCharacteristics outCharacteristics = new KeyCharacteristics(); + int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics); + assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc); + + args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); + args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, + true, args, null); + assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode); + IBinder first = result.token; + // Implementation detail: softkeymaster supports 16 concurrent operations + for (int i = 0; i < 16; i++) { + result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, null); + assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode); + } + // At this point the first operation should be pruned. + assertEquals("Operation should be pruned", KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, + mKeyStore.update(first, null, new byte[] {0x01}).resultCode); + } + + public void testAuthNeeded() throws Exception { + String name = "test"; + KeymasterArguments args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7); + args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256); + args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB); + args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 1); + + KeyCharacteristics outCharacteristics = new KeyCharacteristics(); + int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics); + assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc); + OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, + true, args, null); + assertEquals("Begin should expect authorization", KeyStore.OP_AUTH_NEEDED, + result.resultCode); + IBinder token = result.token; + result = mKeyStore.update(token, null, new byte[] {0x01, 0x02, 0x03, 0x04}); + assertEquals("Update should require authorization", + KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED, result.resultCode); + } + + public void testPasswordRemovalEncryptedEntry() throws Exception { + mKeyStore.onUserPasswordChanged("test"); + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, + KeyStore.FLAG_ENCRYPTED)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME))); + mKeyStore.onUserPasswordChanged(""); + // Removing the password should have deleted all entries using FLAG_ENCRYPTED + assertNull(mKeyStore.get(TEST_KEYNAME)); + assertFalse(mKeyStore.contains(TEST_KEYNAME)); + } + + public void testPasswordRemovalUnencryptedEntry() throws Exception { + mKeyStore.onUserPasswordChanged("test"); + assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, + KeyStore.FLAG_NONE)); + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME))); + mKeyStore.onUserPasswordChanged(""); + // Removing the password should not delete unencrypted entries. + assertTrue(mKeyStore.contains(TEST_KEYNAME)); + assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME))); + } +} diff --git a/keystore/tests/src/android/security/SystemKeyStoreTest.java b/keystore/tests/src/android/security/SystemKeyStoreTest.java new file mode 100644 index 000000000000..ecf7cbcb41c0 --- /dev/null +++ b/keystore/tests/src/android/security/SystemKeyStoreTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security; + +import android.app.Activity; +import android.security.SystemKeyStore; +import android.test.ActivityUnitTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Junit / Instrumentation test case for KeyStore class + * + * Running the test suite: + * + * runtest keystore-unit + * + * Or this individual test case: + * + * runtest --path frameworks/base/keystore/tests/src/android/security/SystemKeyStoreTest.java + */ +@MediumTest +public class SystemKeyStoreTest extends ActivityUnitTestCase<Activity> { + + private static final String keyName = "TestKey"; + private static final String keyName2 = "TestKey2"; + private SystemKeyStore mSysKeyStore = null; + + public SystemKeyStoreTest() { + super(Activity.class); + } + + @Override + protected void setUp() throws Exception { + mSysKeyStore = SystemKeyStore.getInstance(); + try { + mSysKeyStore.deleteKey(keyName); + mSysKeyStore.deleteKey(keyName2); + } catch (Exception e) { } + super.setUp(); + } + + @Override + protected void tearDown() throws Exception { + try { + mSysKeyStore.deleteKey(keyName); + mSysKeyStore.deleteKey(keyName2); + } catch (Exception e) { } + super.tearDown(); + } + + public void testBasicAccess() throws Exception { + try { + byte[] newKey = mSysKeyStore.generateNewKey(128, "AES", keyName); + assertNotNull(newKey); + byte[] recKey = mSysKeyStore.retrieveKey(keyName); + assertEquals(newKey.length, recKey.length); + for (int i = 0; i < newKey.length; i++) { + assertEquals(newKey[i], recKey[i]); + } + mSysKeyStore.deleteKey(keyName); + byte[] nullKey = mSysKeyStore.retrieveKey(keyName); + assertNull(nullKey); + + String newKeyStr = mSysKeyStore.generateNewKeyHexString(128, "AES", keyName2); + assertNotNull(newKeyStr); + String recKeyStr = mSysKeyStore.retrieveKeyHexString(keyName2); + assertEquals(newKeyStr, recKeyStr); + + mSysKeyStore.deleteKey(keyName2); + String nullKey2 = mSysKeyStore.retrieveKeyHexString(keyName2); + assertNull(nullKey2); + } catch (Exception e) { + fail(); + } + } +} diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java new file mode 100644 index 000000000000..1af0b7d4212a --- /dev/null +++ b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java @@ -0,0 +1,432 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore; + +import android.security.Credentials; +import android.security.KeyPairGeneratorSpec; +import android.security.KeyStore; +import android.security.keymaster.ExportResult; +import android.security.keymaster.KeymasterDefs; +import android.test.AndroidTestCase; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.RSAKeyGenParameterSpec; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; + +import javax.security.auth.x500.X500Principal; + +public class AndroidKeyPairGeneratorTest extends AndroidTestCase { + private android.security.KeyStore mAndroidKeyStore; + + private java.security.KeyPairGenerator mGenerator; + + private static final String TEST_ALIAS_1 = "test1"; + + private static final String TEST_ALIAS_2 = "test2"; + + private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1"); + + private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2"); + + private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE; + + private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L); + + private static final long NOW_MILLIS = System.currentTimeMillis(); + + /* We have to round this off because X509v3 doesn't store milliseconds. */ + private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L)); + + @SuppressWarnings("deprecation") + private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1); + + @Override + protected void setUp() throws Exception { + mAndroidKeyStore = android.security.KeyStore.getInstance(); + + assertTrue(mAndroidKeyStore.reset()); + + assertFalse(mAndroidKeyStore.isUnlocked()); + + mGenerator = java.security.KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); + } + + private void setupPassword() { + assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111")); + assertTrue(mAndroidKeyStore.isUnlocked()); + + String[] aliases = mAndroidKeyStore.list(""); + assertNotNull(aliases); + assertEquals(0, aliases.length); + } + + public void testKeyPairGenerator_Initialize_Params_Encrypted_Success() throws Exception { + setupPassword(); + + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .setEncryptionRequired() + .build()); + } + + public void testKeyPairGenerator_Initialize_KeySize_Encrypted_Failure() throws Exception { + setupPassword(); + + try { + mGenerator.initialize(1024); + fail("KeyPairGenerator should not support setting the key size"); + } catch (IllegalArgumentException success) { + } + } + + public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Encrypted_Failure() + throws Exception { + setupPassword(); + + try { + mGenerator.initialize(1024, new SecureRandom()); + fail("KeyPairGenerator should not support setting the key size"); + } catch (IllegalArgumentException success) { + } + } + + public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Encrypted_Failure() + throws Exception { + setupPassword(); + + mGenerator.initialize( + new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setKeyType("RSA") + .setKeySize(1024) + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .setEncryptionRequired() + .build(), + new SecureRandom()); + } + + public void testKeyPairGenerator_GenerateKeyPair_Encrypted_Success() throws Exception { + setupPassword(); + + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .setEncryptionRequired() + .build()); + + final KeyPair pair = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair); + + assertKeyPairCorrect(pair, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + } + + public void testKeyPairGenerator_GenerateKeyPair_EC_Unencrypted_Success() throws Exception { + KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore"); + generator.initialize(new KeyGenParameterSpec.Builder( + TEST_ALIAS_1, + KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY) + .setCertificateSubject(TEST_DN_1) + .setCertificateSerialNumber(TEST_SERIAL_1) + .setCertificateNotBefore(NOW) + .setCertificateNotAfter(NOW_PLUS_10_YEARS) + .setDigests(KeyProperties.DIGEST_SHA256) + .build()); + + final KeyPair pair = generator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair); + + assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + } + + public void testKeyPairGenerator_Legacy_GenerateKeyPair_EC_Unencrypted_Success() + throws Exception { + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setKeyType("EC") + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .build()); + + final KeyPair pair = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair); + + assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + } + + public void testKeyPairGenerator_GenerateKeyPair_EC_P521_Unencrypted_Success() throws Exception { + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setKeyType("EC") + .setKeySize(521) + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .build()); + + final KeyPair pair = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair); + + assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 521, null, TEST_DN_1, TEST_SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + } + + public void testKeyPairGenerator_GenerateKeyPair_RSA_Unencrypted_Success() throws Exception { + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .build()); + + final KeyPair pair = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair); + + assertKeyPairCorrect(pair, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + } + + public void testKeyPairGenerator_GenerateKeyPair_RSA_WithParams_Unencrypted_Success() + throws Exception { + AlgorithmParameterSpec spec = new RSAKeyGenParameterSpec(1024, BigInteger.valueOf(3L)); + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setKeySize(1024) + .setAlgorithmParameterSpec(spec) + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .build()); + + final KeyPair pair = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair); + + assertKeyPairCorrect(pair, TEST_ALIAS_1, "RSA", 1024, spec, TEST_DN_1, TEST_SERIAL_1, NOW, + NOW_PLUS_10_YEARS); + } + + public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception { + // Generate the first key + { + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .build()); + final KeyPair pair1 = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair1); + assertKeyPairCorrect(pair1, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, + NOW, NOW_PLUS_10_YEARS); + } + + // Replace the original key + { + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_2) + .setSubject(TEST_DN_2) + .setSerialNumber(TEST_SERIAL_2) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .build()); + final KeyPair pair2 = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair2); + assertKeyPairCorrect(pair2, TEST_ALIAS_2, "RSA", 2048, null, TEST_DN_2, TEST_SERIAL_2, + NOW, NOW_PLUS_10_YEARS); + } + } + + public void testKeyPairGenerator_GenerateKeyPair_Replaced_UnencryptedToEncrypted_Success() + throws Exception { + // Generate the first key + { + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setSubject(TEST_DN_1) + .setSerialNumber(TEST_SERIAL_1) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .build()); + final KeyPair pair1 = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair1); + assertKeyPairCorrect(pair1, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, + NOW, NOW_PLUS_10_YEARS); + } + + // Attempt to replace previous key + { + mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext()) + .setAlias(TEST_ALIAS_1) + .setSubject(TEST_DN_2) + .setSerialNumber(TEST_SERIAL_2) + .setStartDate(NOW) + .setEndDate(NOW_PLUS_10_YEARS) + .setEncryptionRequired() + .build()); + try { + mGenerator.generateKeyPair(); + fail("Should not be able to generate encrypted key while not initialized"); + } catch (IllegalStateException expected) { + } + + assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111")); + assertTrue(mAndroidKeyStore.isUnlocked()); + + final KeyPair pair2 = mGenerator.generateKeyPair(); + assertNotNull("The KeyPair returned should not be null", pair2); + assertKeyPairCorrect(pair2, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_2, TEST_SERIAL_2, + NOW, NOW_PLUS_10_YEARS); + } + } + + private void assertKeyPairCorrect(KeyPair pair, String alias, String keyType, int keySize, + AlgorithmParameterSpec spec, X500Principal dn, BigInteger serial, Date start, Date end) + throws Exception { + final PublicKey pubKey = pair.getPublic(); + assertNotNull("The PublicKey for the KeyPair should be not null", pubKey); + assertEquals(keyType, pubKey.getAlgorithm()); + + if ("EC".equalsIgnoreCase(keyType)) { + assertEquals("Curve should be what was specified during initialization", keySize, + ((ECPublicKey) pubKey).getParams().getCurve().getField().getFieldSize()); + } else if ("RSA".equalsIgnoreCase(keyType)) { + RSAPublicKey rsaPubKey = (RSAPublicKey) pubKey; + assertEquals("Modulus size should be what is specified during initialization", + (keySize + 7) & ~7, (rsaPubKey.getModulus().bitLength() + 7) & ~7); + if (spec != null) { + RSAKeyGenParameterSpec params = (RSAKeyGenParameterSpec) spec; + assertEquals((keySize + 7) & ~7, (params.getKeysize() + 7) & ~7); + assertEquals(params.getPublicExponent(), rsaPubKey.getPublicExponent()); + } + } + + final PrivateKey privKey = pair.getPrivate(); + assertNotNull("The PrivateKey for the KeyPair should be not null", privKey); + assertEquals(keyType, privKey.getAlgorithm()); + + if ("EC".equalsIgnoreCase(keyType)) { + assertTrue("EC private key must be instanceof ECKey: " + privKey.getClass().getName(), + privKey instanceof ECKey); + assertEquals("Private and public key must have the same EC parameters", + ((ECKey) pubKey).getParams(), ((ECKey) privKey).getParams()); + } else if ("RSA".equalsIgnoreCase(keyType)) { + assertTrue("RSA private key must be instance of RSAKey: " + + privKey.getClass().getName(), + privKey instanceof RSAKey); + assertEquals("Private and public key must have the same RSA modulus", + ((RSAKey) pubKey).getModulus(), ((RSAKey) privKey).getModulus()); + } + + final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias); + assertNotNull("The user certificate should exist for the generated entry", userCertBytes); + + final CertificateFactory cf = CertificateFactory.getInstance("X.509"); + final Certificate userCert = + cf.generateCertificate(new ByteArrayInputStream(userCertBytes)); + + assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate); + + final X509Certificate x509userCert = (X509Certificate) userCert; + + assertEquals( + "Public key used to sign certificate should have the same algorithm as in KeyPair", + pubKey.getAlgorithm(), x509userCert.getPublicKey().getAlgorithm()); + + assertEquals("PublicKey used to sign certificate should match one returned in KeyPair", + pubKey, + AndroidKeyStoreProvider.getAndroidKeyStorePublicKey( + Credentials.USER_PRIVATE_KEY + alias, + KeyStore.UID_SELF, + x509userCert.getPublicKey().getAlgorithm(), + x509userCert.getPublicKey().getEncoded())); + + assertEquals("The Subject DN should be the one passed into the params", dn, + x509userCert.getSubjectDN()); + + assertEquals("The Issuer DN should be the same as the Subject DN", dn, + x509userCert.getIssuerDN()); + + assertEquals("The Serial should be the one passed into the params", serial, + x509userCert.getSerialNumber()); + + assertDateEquals("The notBefore date should be the one passed into the params", start, + x509userCert.getNotBefore()); + + assertDateEquals("The notAfter date should be the one passed into the params", end, + x509userCert.getNotAfter()); + + // Assert that the cert's signature verifies using the public key from generated KeyPair + x509userCert.verify(pubKey); + // Assert that the cert's signature verifies using the public key from the cert itself. + x509userCert.verify(x509userCert.getPublicKey()); + + final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias); + assertNull("A list of CA certificates should not exist for the generated entry", caCerts); + + ExportResult exportResult = mAndroidKeyStore.exportKey( + Credentials.USER_PRIVATE_KEY + alias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null); + assertEquals(KeyStore.NO_ERROR, exportResult.resultCode); + final byte[] pubKeyBytes = exportResult.exportData; + assertNotNull("The keystore should return the public key for the generated key", + pubKeyBytes); + assertTrue("Public key X.509 format should be as expected", + Arrays.equals(pubKey.getEncoded(), pubKeyBytes)); + } + + private static void assertDateEquals(String message, Date date1, Date date2) throws Exception { + SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss"); + + String result1 = formatter.format(date1); + String result2 = formatter.format(date2); + + assertEquals(message, result1, result2); + } +} diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java new file mode 100644 index 000000000000..aa718dca168e --- /dev/null +++ b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java @@ -0,0 +1,2210 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore; + +import com.android.org.bouncycastle.x509.X509V3CertificateGenerator; + +import com.android.org.conscrypt.NativeConstants; + +import android.security.Credentials; +import android.security.KeyStore; +import android.security.KeyStoreParameter; +import android.test.AndroidTestCase; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyStore.Entry; +import java.security.KeyStore.PrivateKeyEntry; +import java.security.KeyStore.TrustedCertificateEntry; +import java.security.KeyStoreException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECKey; +import java.security.interfaces.RSAKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import javax.security.auth.x500.X500Principal; + +public class AndroidKeyStoreTest extends AndroidTestCase { + private android.security.KeyStore mAndroidKeyStore; + + private java.security.KeyStore mKeyStore; + + private static final String TEST_ALIAS_1 = "test1"; + + private static final String TEST_ALIAS_2 = "test2"; + + private static final String TEST_ALIAS_3 = "test3"; + + private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1"); + + private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2"); + + private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE; + + private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L); + + private static final long NOW_MILLIS = System.currentTimeMillis(); + + /* We have to round this off because X509v3 doesn't store milliseconds. */ + private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L)); + + @SuppressWarnings("deprecation") + private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1); + + /* + * The keys and certificates below are generated with: + * + * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem + * openssl req -newkey rsa:1024 -keyout userkey.pem -nodes -days 3650 -out userkey.req + * mkdir -p demoCA/newcerts + * touch demoCA/index.txt + * echo "01" > demoCA/serial + * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650 + */ + + /** + * Generated from above and converted with: + * + * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] FAKE_RSA_CA_1 = { + (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xce, (byte) 0x30, (byte) 0x82, + (byte) 0x02, (byte) 0x37, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, + (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xe1, (byte) 0x6a, + (byte) 0xa2, (byte) 0xf4, (byte) 0x2e, (byte) 0x55, (byte) 0x48, (byte) 0x0a, + (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, + (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31, + (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, + (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, + (byte) 0x41, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, + (byte) 0x4d, (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, + (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, + (byte) 0x77, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, + (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, + (byte) 0x64, (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, + (byte) 0x20, (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, + (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32, + (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x34, (byte) 0x31, (byte) 0x36, + (byte) 0x35, (byte) 0x35, (byte) 0x34, (byte) 0x34, (byte) 0x5a, (byte) 0x17, + (byte) 0x0d, (byte) 0x32, (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31, + (byte) 0x32, (byte) 0x31, (byte) 0x36, (byte) 0x35, (byte) 0x35, (byte) 0x34, + (byte) 0x34, (byte) 0x5a, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, + (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, + (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, + (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, + (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, + (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, + (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, + (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, + (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30, + (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, + (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, + (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, + (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, + (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa3, (byte) 0x72, + (byte) 0xab, (byte) 0xd0, (byte) 0xe4, (byte) 0xad, (byte) 0x2f, (byte) 0xe7, + (byte) 0xe2, (byte) 0x79, (byte) 0x07, (byte) 0x36, (byte) 0x3d, (byte) 0x0c, + (byte) 0x8d, (byte) 0x42, (byte) 0x9a, (byte) 0x0a, (byte) 0x33, (byte) 0x64, + (byte) 0xb3, (byte) 0xcd, (byte) 0xb2, (byte) 0xd7, (byte) 0x3a, (byte) 0x42, + (byte) 0x06, (byte) 0x77, (byte) 0x45, (byte) 0x29, (byte) 0xe9, (byte) 0xcb, + (byte) 0xb7, (byte) 0x4a, (byte) 0xd6, (byte) 0xee, (byte) 0xad, (byte) 0x01, + (byte) 0x91, (byte) 0x9b, (byte) 0x0c, (byte) 0x59, (byte) 0xa1, (byte) 0x03, + (byte) 0xfa, (byte) 0xf0, (byte) 0x5a, (byte) 0x7c, (byte) 0x4f, (byte) 0xf7, + (byte) 0x8d, (byte) 0x36, (byte) 0x0f, (byte) 0x1f, (byte) 0x45, (byte) 0x7d, + (byte) 0x1b, (byte) 0x31, (byte) 0xa1, (byte) 0x35, (byte) 0x0b, (byte) 0x00, + (byte) 0xed, (byte) 0x7a, (byte) 0xb6, (byte) 0xc8, (byte) 0x4e, (byte) 0xa9, + (byte) 0x86, (byte) 0x4c, (byte) 0x7b, (byte) 0x99, (byte) 0x57, (byte) 0x41, + (byte) 0x12, (byte) 0xef, (byte) 0x6b, (byte) 0xbc, (byte) 0x3d, (byte) 0x60, + (byte) 0xf2, (byte) 0x99, (byte) 0x1a, (byte) 0xcd, (byte) 0xed, (byte) 0x56, + (byte) 0xa4, (byte) 0xe5, (byte) 0x36, (byte) 0x9f, (byte) 0x24, (byte) 0x1f, + (byte) 0xdc, (byte) 0x89, (byte) 0x40, (byte) 0xc8, (byte) 0x99, (byte) 0x92, + (byte) 0xab, (byte) 0x4a, (byte) 0xb5, (byte) 0x61, (byte) 0x45, (byte) 0x62, + (byte) 0xff, (byte) 0xa3, (byte) 0x45, (byte) 0x65, (byte) 0xaf, (byte) 0xf6, + (byte) 0x27, (byte) 0x30, (byte) 0x51, (byte) 0x0e, (byte) 0x0e, (byte) 0xeb, + (byte) 0x79, (byte) 0x0c, (byte) 0xbe, (byte) 0xb3, (byte) 0x0a, (byte) 0x6f, + (byte) 0x29, (byte) 0x06, (byte) 0xdc, (byte) 0x2f, (byte) 0x6b, (byte) 0x51, + (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, + (byte) 0x81, (byte) 0xb1, (byte) 0x30, (byte) 0x81, (byte) 0xae, (byte) 0x30, + (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, + (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x33, (byte) 0x05, + (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60, (byte) 0xc7, (byte) 0xf9, + (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c, (byte) 0x8f, (byte) 0x6d, + (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e, (byte) 0x5d, (byte) 0x51, + (byte) 0x30, (byte) 0x7f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, + (byte) 0x23, (byte) 0x04, (byte) 0x78, (byte) 0x30, (byte) 0x76, (byte) 0x80, + (byte) 0x14, (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f, + (byte) 0x60, (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73, + (byte) 0x5c, (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97, + (byte) 0x8e, (byte) 0x5d, (byte) 0x51, (byte) 0xa1, (byte) 0x53, (byte) 0xa4, + (byte) 0x51, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30, + (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, + (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31, + (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f, + (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, + (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, + (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e, + (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, + (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43, + (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x82, (byte) 0x09, + (byte) 0x00, (byte) 0xe1, (byte) 0x6a, (byte) 0xa2, (byte) 0xf4, (byte) 0x2e, + (byte) 0x55, (byte) 0x48, (byte) 0x0a, (byte) 0x30, (byte) 0x0c, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05, + (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30, + (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, + (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, + (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00, + (byte) 0x8c, (byte) 0x30, (byte) 0x42, (byte) 0xfa, (byte) 0xeb, (byte) 0x1a, + (byte) 0x26, (byte) 0xeb, (byte) 0xda, (byte) 0x56, (byte) 0x32, (byte) 0xf2, + (byte) 0x9d, (byte) 0xa5, (byte) 0x24, (byte) 0xd8, (byte) 0x3a, (byte) 0xda, + (byte) 0x30, (byte) 0xa6, (byte) 0x8b, (byte) 0x46, (byte) 0xfe, (byte) 0xfe, + (byte) 0xdb, (byte) 0xf1, (byte) 0xe6, (byte) 0xe1, (byte) 0x7c, (byte) 0x1b, + (byte) 0xe7, (byte) 0x77, (byte) 0x00, (byte) 0xa1, (byte) 0x1c, (byte) 0x19, + (byte) 0x17, (byte) 0x73, (byte) 0xb0, (byte) 0xf0, (byte) 0x9d, (byte) 0xf3, + (byte) 0x4f, (byte) 0xb6, (byte) 0xbc, (byte) 0xc7, (byte) 0x47, (byte) 0x85, + (byte) 0x2a, (byte) 0x4a, (byte) 0xa1, (byte) 0xa5, (byte) 0x58, (byte) 0xf5, + (byte) 0xc5, (byte) 0x1a, (byte) 0x51, (byte) 0xb1, (byte) 0x04, (byte) 0x80, + (byte) 0xee, (byte) 0x3a, (byte) 0xec, (byte) 0x2f, (byte) 0xe1, (byte) 0xfd, + (byte) 0x58, (byte) 0xeb, (byte) 0xed, (byte) 0x82, (byte) 0x9e, (byte) 0x38, + (byte) 0xa3, (byte) 0x24, (byte) 0x75, (byte) 0xf7, (byte) 0x3e, (byte) 0xc2, + (byte) 0xc5, (byte) 0x27, (byte) 0xeb, (byte) 0x6f, (byte) 0x7b, (byte) 0x50, + (byte) 0xda, (byte) 0x43, (byte) 0xdc, (byte) 0x3b, (byte) 0x0b, (byte) 0x6f, + (byte) 0x78, (byte) 0x8f, (byte) 0xb0, (byte) 0x66, (byte) 0xe1, (byte) 0x12, + (byte) 0x87, (byte) 0x5f, (byte) 0x97, (byte) 0x7b, (byte) 0xca, (byte) 0x14, + (byte) 0x79, (byte) 0xf7, (byte) 0xe8, (byte) 0x6c, (byte) 0x72, (byte) 0xdb, + (byte) 0x91, (byte) 0x65, (byte) 0x17, (byte) 0x54, (byte) 0xe0, (byte) 0x74, + (byte) 0x1d, (byte) 0xac, (byte) 0x47, (byte) 0x04, (byte) 0x12, (byte) 0xe0, + (byte) 0xc3, (byte) 0x66, (byte) 0x19, (byte) 0x05, (byte) 0x2e, (byte) 0x7e, + (byte) 0xf1, (byte) 0x61 + }; + + /** + * Generated from above and converted with: + * + * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] FAKE_RSA_KEY_1 = new byte[] { + (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01, + (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, + (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82, + (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e, + (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81, + (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b, + (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66, + (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a, + (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02, + (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3, + (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d, + (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67, + (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb, + (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2, + (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79, + (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce, + (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08, + (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b, + (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4, + (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d, + (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23, + (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08, + (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1, + (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4, + (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16, + (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e, + (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01, + (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16, + (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98, + (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf, + (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a, + (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2, + (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc, + (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5, + (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a, + (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b, + (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9, + (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12, + (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e, + (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d, + (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2, + (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d, + (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc, + (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98, + (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96, + (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30, + (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e, + (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad, + (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f, + (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89, + (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13, + (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a, + (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e, + (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa, + (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47, + (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44, + (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22, + (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10, + (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45, + (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4, + (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda, + (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1, + (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab, + (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7, + (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc, + (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d, + (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82, + (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3, + (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a, + (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9, + (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6, + (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00, + (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd, + (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb, + (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4, + (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0, + (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2, + (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce, + (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a, + (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21, + (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d, + (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1, + (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41, + (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce, + (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0, + (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40, + (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a, + (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c, + (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90, + (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf, + (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb, + (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14, + (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab, + (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02, + (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67, + (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d, + (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d, + (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b, + (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2, + (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28, + (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd, + (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d, + (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b, + (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1, + (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51 + }; + + /** + * Generated from above and converted with: + * + * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] FAKE_RSA_USER_1 = new byte[] { + (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x95, (byte) 0x30, (byte) 0x82, + (byte) 0x01, (byte) 0xfe, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, + (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, + (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30, + (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, + (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31, + (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f, + (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e, + (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31, + (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e, + (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, + (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43, + (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30, (byte) 0x1e, + (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32, (byte) 0x30, (byte) 0x38, + (byte) 0x31, (byte) 0x34, (byte) 0x32, (byte) 0x33, (byte) 0x32, (byte) 0x35, + (byte) 0x34, (byte) 0x38, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, + (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x32, + (byte) 0x33, (byte) 0x32, (byte) 0x35, (byte) 0x34, (byte) 0x38, (byte) 0x5a, + (byte) 0x30, (byte) 0x55, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, + (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b, (byte) 0x30, + (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, + (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31, (byte) 0x1b, + (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e, (byte) 0x64, + (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x54, + (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43, (byte) 0x61, + (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x31, (byte) 0x1c, (byte) 0x30, + (byte) 0x1a, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, + (byte) 0x13, (byte) 0x13, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, + (byte) 0x65, (byte) 0x72, (byte) 0x31, (byte) 0x2e, (byte) 0x65, (byte) 0x78, + (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e, + (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x81, (byte) 0x9f, + (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, + (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d, + (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, + (byte) 0x81, (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, + (byte) 0x5b, (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, + (byte) 0x66, (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, + (byte) 0x8a, (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, + (byte) 0x02, (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, + (byte) 0xf3, (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, + (byte) 0x6d, (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, + (byte) 0x67, (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, + (byte) 0xcb, (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, + (byte) 0xe2, (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, + (byte) 0x79, (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, + (byte) 0xce, (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, + (byte) 0x08, (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, + (byte) 0x3b, (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, + (byte) 0xc4, (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, + (byte) 0x0d, (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, + (byte) 0x23, (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, + (byte) 0x08, (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, + (byte) 0xf1, (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, + (byte) 0xb4, (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, + (byte) 0x16, (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, + (byte) 0x9e, (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, + (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, + (byte) 0x79, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, + (byte) 0x30, (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, + (byte) 0x48, (byte) 0x01, (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, + (byte) 0x0d, (byte) 0x04, (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, + (byte) 0x70, (byte) 0x65, (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, + (byte) 0x20, (byte) 0x47, (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, + (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, + (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, + (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, + (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x32, (byte) 0xa1, (byte) 0x1e, + (byte) 0x6b, (byte) 0x69, (byte) 0x04, (byte) 0xfe, (byte) 0xb3, (byte) 0xcd, + (byte) 0xf8, (byte) 0xbb, (byte) 0x14, (byte) 0xcd, (byte) 0xff, (byte) 0xd4, + (byte) 0x16, (byte) 0xc3, (byte) 0xab, (byte) 0x44, (byte) 0x2f, (byte) 0x30, + (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, + (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, + (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60, + (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c, + (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e, + (byte) 0x5d, (byte) 0x51, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, + (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, + (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, + (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x46, (byte) 0x42, (byte) 0xef, + (byte) 0x56, (byte) 0x89, (byte) 0x78, (byte) 0x90, (byte) 0x38, (byte) 0x24, + (byte) 0x9f, (byte) 0x8c, (byte) 0x7a, (byte) 0xce, (byte) 0x7a, (byte) 0xa5, + (byte) 0xb5, (byte) 0x1e, (byte) 0x74, (byte) 0x96, (byte) 0x34, (byte) 0x49, + (byte) 0x8b, (byte) 0xed, (byte) 0x44, (byte) 0xb3, (byte) 0xc9, (byte) 0x05, + (byte) 0xd7, (byte) 0x48, (byte) 0x55, (byte) 0x52, (byte) 0x59, (byte) 0x15, + (byte) 0x0b, (byte) 0xaa, (byte) 0x16, (byte) 0x86, (byte) 0xd2, (byte) 0x8e, + (byte) 0x16, (byte) 0x99, (byte) 0xe8, (byte) 0x5f, (byte) 0x11, (byte) 0x71, + (byte) 0x42, (byte) 0x55, (byte) 0xd1, (byte) 0xc4, (byte) 0x6f, (byte) 0x2e, + (byte) 0xa9, (byte) 0x64, (byte) 0x6f, (byte) 0xd8, (byte) 0xfd, (byte) 0x43, + (byte) 0x13, (byte) 0x24, (byte) 0xaa, (byte) 0x67, (byte) 0xe6, (byte) 0xf5, + (byte) 0xca, (byte) 0x80, (byte) 0x5e, (byte) 0x3a, (byte) 0x3e, (byte) 0xcc, + (byte) 0x4f, (byte) 0xba, (byte) 0x87, (byte) 0xe6, (byte) 0xae, (byte) 0xbf, + (byte) 0x8f, (byte) 0xd5, (byte) 0x28, (byte) 0x38, (byte) 0x58, (byte) 0x30, + (byte) 0x24, (byte) 0xf6, (byte) 0x53, (byte) 0x5b, (byte) 0x41, (byte) 0x53, + (byte) 0xe6, (byte) 0x45, (byte) 0xbc, (byte) 0xbe, (byte) 0xe6, (byte) 0xbb, + (byte) 0x5d, (byte) 0xd8, (byte) 0xa7, (byte) 0xf9, (byte) 0x64, (byte) 0x99, + (byte) 0x04, (byte) 0x43, (byte) 0x75, (byte) 0xd7, (byte) 0x2d, (byte) 0x32, + (byte) 0x0a, (byte) 0x94, (byte) 0xaf, (byte) 0x06, (byte) 0x34, (byte) 0xae, + (byte) 0x46, (byte) 0xbd, (byte) 0xda, (byte) 0x00, (byte) 0x0e, (byte) 0x25, + (byte) 0xc2, (byte) 0xf7, (byte) 0xc9, (byte) 0xc3, (byte) 0x65, (byte) 0xd2, + (byte) 0x08, (byte) 0x41, (byte) 0x0a, (byte) 0xf3, (byte) 0x72 + }; + + /* + * The keys and certificates below are generated with: + * + * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem + * openssl ecparam -name prime256v1 -out ecparam.pem + * openssl req -newkey ec:ecparam.pem -keyout userkey.pem -nodes -days 3650 -out userkey.req + * mkdir -p demoCA/newcerts + * touch demoCA/index.txt + * echo "01" > demoCA/serial + * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650 + */ + + /** + * Generated from above and converted with: + * + * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] FAKE_EC_CA_1 = { + (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x58, (byte) 0x30, (byte) 0x82, + (byte) 0x01, (byte) 0xc1, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, + (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xe1, (byte) 0xb2, + (byte) 0x8c, (byte) 0x04, (byte) 0x95, (byte) 0xeb, (byte) 0x10, (byte) 0xcb, + (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, + (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x45, (byte) 0x31, + (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, + (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, + (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, + (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30, + (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, + (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, + (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57, + (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73, + (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c, + (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, + (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x37, + (byte) 0x31, (byte) 0x36, (byte) 0x32, (byte) 0x38, (byte) 0x32, (byte) 0x38, + (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x33, (byte) 0x30, + (byte) 0x38, (byte) 0x32, (byte) 0x35, (byte) 0x31, (byte) 0x36, (byte) 0x32, + (byte) 0x38, (byte) 0x32, (byte) 0x38, (byte) 0x5a, (byte) 0x30, (byte) 0x45, + (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, + (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, + (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, + (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, + (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x0a, (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, + (byte) 0x65, (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, + (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, + (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, + (byte) 0x4c, (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x81, (byte) 0x9f, + (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, + (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d, + (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81, + (byte) 0x81, (byte) 0x00, (byte) 0xb5, (byte) 0xf6, (byte) 0x08, (byte) 0x0f, + (byte) 0xc4, (byte) 0x4d, (byte) 0xe4, (byte) 0x0d, (byte) 0x34, (byte) 0x1d, + (byte) 0xe2, (byte) 0x23, (byte) 0x18, (byte) 0x63, (byte) 0x03, (byte) 0xf7, + (byte) 0x14, (byte) 0x0e, (byte) 0x98, (byte) 0xcd, (byte) 0x45, (byte) 0x1f, + (byte) 0xfe, (byte) 0xfb, (byte) 0x09, (byte) 0x3f, (byte) 0x5d, (byte) 0x36, + (byte) 0x3b, (byte) 0x0f, (byte) 0xf9, (byte) 0x5e, (byte) 0x86, (byte) 0x56, + (byte) 0x64, (byte) 0xd7, (byte) 0x3f, (byte) 0xae, (byte) 0x33, (byte) 0x09, + (byte) 0xd3, (byte) 0xdd, (byte) 0x06, (byte) 0x17, (byte) 0x26, (byte) 0xdc, + (byte) 0xa2, (byte) 0x8c, (byte) 0x3c, (byte) 0x65, (byte) 0xed, (byte) 0x03, + (byte) 0x82, (byte) 0x78, (byte) 0x9b, (byte) 0xee, (byte) 0xe3, (byte) 0x98, + (byte) 0x58, (byte) 0xe1, (byte) 0xf1, (byte) 0xa0, (byte) 0x85, (byte) 0xae, + (byte) 0x63, (byte) 0x84, (byte) 0x41, (byte) 0x46, (byte) 0xa7, (byte) 0x4f, + (byte) 0xdc, (byte) 0xbb, (byte) 0x1c, (byte) 0x6e, (byte) 0xec, (byte) 0x7b, + (byte) 0xd5, (byte) 0xab, (byte) 0x3d, (byte) 0x6a, (byte) 0x05, (byte) 0x58, + (byte) 0x0f, (byte) 0x9b, (byte) 0x6a, (byte) 0x67, (byte) 0x4b, (byte) 0xe9, + (byte) 0x2a, (byte) 0x6d, (byte) 0x96, (byte) 0x11, (byte) 0x53, (byte) 0x95, + (byte) 0x78, (byte) 0xaa, (byte) 0xd1, (byte) 0x91, (byte) 0x4a, (byte) 0xf8, + (byte) 0x54, (byte) 0x52, (byte) 0x6d, (byte) 0xb9, (byte) 0xca, (byte) 0x74, + (byte) 0x81, (byte) 0xf8, (byte) 0x99, (byte) 0x64, (byte) 0xd1, (byte) 0x4f, + (byte) 0x01, (byte) 0x38, (byte) 0x4f, (byte) 0x08, (byte) 0x5c, (byte) 0x31, + (byte) 0xcb, (byte) 0x7c, (byte) 0x5c, (byte) 0x78, (byte) 0x5d, (byte) 0x47, + (byte) 0xd9, (byte) 0xf0, (byte) 0x1a, (byte) 0xeb, (byte) 0x02, (byte) 0x03, + (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, (byte) 0x50, (byte) 0x30, + (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, + (byte) 0x5f, (byte) 0x5b, (byte) 0x5e, (byte) 0xac, (byte) 0x29, (byte) 0xfa, + (byte) 0xa1, (byte) 0x9f, (byte) 0x9e, (byte) 0xad, (byte) 0x46, (byte) 0xe1, + (byte) 0xbc, (byte) 0x20, (byte) 0x72, (byte) 0xcf, (byte) 0x4a, (byte) 0xd4, + (byte) 0xfa, (byte) 0xe3, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18, (byte) 0x30, + (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x5f, (byte) 0x5b, (byte) 0x5e, + (byte) 0xac, (byte) 0x29, (byte) 0xfa, (byte) 0xa1, (byte) 0x9f, (byte) 0x9e, + (byte) 0xad, (byte) 0x46, (byte) 0xe1, (byte) 0xbc, (byte) 0x20, (byte) 0x72, + (byte) 0xcf, (byte) 0x4a, (byte) 0xd4, (byte) 0xfa, (byte) 0xe3, (byte) 0x30, + (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, + (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, + (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, + (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, + (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, + (byte) 0x81, (byte) 0x00, (byte) 0xa1, (byte) 0x4a, (byte) 0xe6, (byte) 0xfc, + (byte) 0x7f, (byte) 0x17, (byte) 0xaa, (byte) 0x65, (byte) 0x4a, (byte) 0x34, + (byte) 0xde, (byte) 0x69, (byte) 0x67, (byte) 0x54, (byte) 0x4d, (byte) 0xa2, + (byte) 0xc2, (byte) 0x98, (byte) 0x02, (byte) 0x43, (byte) 0x6a, (byte) 0x0e, + (byte) 0x0b, (byte) 0x7f, (byte) 0xa4, (byte) 0x46, (byte) 0xaf, (byte) 0xa4, + (byte) 0x65, (byte) 0xa0, (byte) 0xdb, (byte) 0xf1, (byte) 0x5b, (byte) 0xd5, + (byte) 0x09, (byte) 0xbc, (byte) 0xee, (byte) 0x37, (byte) 0x51, (byte) 0x19, + (byte) 0x36, (byte) 0xc0, (byte) 0x90, (byte) 0xd3, (byte) 0x5f, (byte) 0xf3, + (byte) 0x4f, (byte) 0xb9, (byte) 0x08, (byte) 0x45, (byte) 0x0e, (byte) 0x01, + (byte) 0x8a, (byte) 0x95, (byte) 0xef, (byte) 0x92, (byte) 0x95, (byte) 0x33, + (byte) 0x78, (byte) 0xdd, (byte) 0x90, (byte) 0xbb, (byte) 0xf3, (byte) 0x06, + (byte) 0x75, (byte) 0xd0, (byte) 0x66, (byte) 0xe6, (byte) 0xd0, (byte) 0x18, + (byte) 0x6e, (byte) 0xeb, (byte) 0x1c, (byte) 0x52, (byte) 0xc3, (byte) 0x2e, + (byte) 0x57, (byte) 0x7d, (byte) 0xa9, (byte) 0x03, (byte) 0xdb, (byte) 0xf4, + (byte) 0x57, (byte) 0x5f, (byte) 0x6c, (byte) 0x7e, (byte) 0x00, (byte) 0x0d, + (byte) 0x8f, (byte) 0xe8, (byte) 0x91, (byte) 0xf7, (byte) 0xae, (byte) 0x24, + (byte) 0x35, (byte) 0x07, (byte) 0xb5, (byte) 0x48, (byte) 0x2d, (byte) 0x36, + (byte) 0x30, (byte) 0x5d, (byte) 0xe9, (byte) 0x49, (byte) 0x2d, (byte) 0xd1, + (byte) 0x5d, (byte) 0xc5, (byte) 0xf4, (byte) 0x33, (byte) 0x77, (byte) 0x3c, + (byte) 0x71, (byte) 0xad, (byte) 0x90, (byte) 0x65, (byte) 0xa9, (byte) 0xc1, + (byte) 0x0b, (byte) 0x5c, (byte) 0x62, (byte) 0x55, (byte) 0x50, (byte) 0x6f, + (byte) 0x9b, (byte) 0xc9, (byte) 0x0d, (byte) 0xee + }; + + /** + * Generated from above and converted with: + * + * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] FAKE_EC_KEY_1 = new byte[] { + (byte) 0x30, (byte) 0x81, (byte) 0x87, (byte) 0x02, (byte) 0x01, (byte) 0x00, + (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, (byte) 0x06, + (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, + (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x04, (byte) 0x6d, (byte) 0x30, + (byte) 0x6b, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x04, (byte) 0x20, + (byte) 0x3a, (byte) 0x8a, (byte) 0x02, (byte) 0xdc, (byte) 0xde, (byte) 0x70, + (byte) 0x84, (byte) 0x45, (byte) 0x34, (byte) 0xaf, (byte) 0xbd, (byte) 0xd5, + (byte) 0x02, (byte) 0x17, (byte) 0x69, (byte) 0x90, (byte) 0x65, (byte) 0x1e, + (byte) 0x87, (byte) 0xf1, (byte) 0x3d, (byte) 0x17, (byte) 0xb6, (byte) 0xf4, + (byte) 0x31, (byte) 0x94, (byte) 0x86, (byte) 0x76, (byte) 0x55, (byte) 0xf7, + (byte) 0xcc, (byte) 0xba, (byte) 0xa1, (byte) 0x44, (byte) 0x03, (byte) 0x42, + (byte) 0x00, (byte) 0x04, (byte) 0xd9, (byte) 0xcf, (byte) 0xe7, (byte) 0x9b, + (byte) 0x23, (byte) 0xc8, (byte) 0xa3, (byte) 0xb8, (byte) 0x33, (byte) 0x14, + (byte) 0xa4, (byte) 0x4d, (byte) 0x75, (byte) 0x90, (byte) 0xf3, (byte) 0xcd, + (byte) 0x43, (byte) 0xe5, (byte) 0x1b, (byte) 0x05, (byte) 0x1d, (byte) 0xf3, + (byte) 0xd0, (byte) 0xa3, (byte) 0xb7, (byte) 0x32, (byte) 0x5f, (byte) 0x79, + (byte) 0xdc, (byte) 0x88, (byte) 0xb8, (byte) 0x4d, (byte) 0xb3, (byte) 0xd1, + (byte) 0x6d, (byte) 0xf7, (byte) 0x75, (byte) 0xf3, (byte) 0xbf, (byte) 0x50, + (byte) 0xa1, (byte) 0xbc, (byte) 0x03, (byte) 0x64, (byte) 0x22, (byte) 0xe6, + (byte) 0x1a, (byte) 0xa1, (byte) 0xe1, (byte) 0x06, (byte) 0x68, (byte) 0x3b, + (byte) 0xbc, (byte) 0x9f, (byte) 0xd3, (byte) 0xae, (byte) 0x77, (byte) 0x5e, + (byte) 0x88, (byte) 0x0c, (byte) 0x5e, (byte) 0x0c, (byte) 0xb2, (byte) 0x38 + }; + + /** + * Generated from above and converted with: + * + * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g' + */ + private static final byte[] FAKE_EC_USER_1 = new byte[] { + (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x51, (byte) 0x30, (byte) 0x82, + (byte) 0x01, (byte) 0xba, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01, + (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d, + (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, + (byte) 0x00, (byte) 0x30, (byte) 0x45, (byte) 0x31, (byte) 0x0b, (byte) 0x30, + (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, + (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13, + (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d, + (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74, + (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x18, + (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6e, + (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64, + (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50, + (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c, (byte) 0x74, (byte) 0x64, + (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x33, + (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x37, (byte) 0x31, (byte) 0x36, + (byte) 0x33, (byte) 0x30, (byte) 0x30, (byte) 0x38, (byte) 0x5a, (byte) 0x17, + (byte) 0x0d, (byte) 0x32, (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32, + (byte) 0x35, (byte) 0x31, (byte) 0x36, (byte) 0x33, (byte) 0x30, (byte) 0x30, + (byte) 0x38, (byte) 0x5a, (byte) 0x30, (byte) 0x62, (byte) 0x31, (byte) 0x0b, + (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, + (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, + (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, + (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, + (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, + (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30, (byte) 0x1f, + (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, + (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72, + (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57, (byte) 0x69, + (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x20, + (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c, (byte) 0x74, + (byte) 0x64, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x12, + (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65, (byte) 0x72, + (byte) 0x2e, (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70, + (byte) 0x6c, (byte) 0x65, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d, + (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, + (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, + (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, + (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x03, + (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0xd9, (byte) 0xcf, (byte) 0xe7, + (byte) 0x9b, (byte) 0x23, (byte) 0xc8, (byte) 0xa3, (byte) 0xb8, (byte) 0x33, + (byte) 0x14, (byte) 0xa4, (byte) 0x4d, (byte) 0x75, (byte) 0x90, (byte) 0xf3, + (byte) 0xcd, (byte) 0x43, (byte) 0xe5, (byte) 0x1b, (byte) 0x05, (byte) 0x1d, + (byte) 0xf3, (byte) 0xd0, (byte) 0xa3, (byte) 0xb7, (byte) 0x32, (byte) 0x5f, + (byte) 0x79, (byte) 0xdc, (byte) 0x88, (byte) 0xb8, (byte) 0x4d, (byte) 0xb3, + (byte) 0xd1, (byte) 0x6d, (byte) 0xf7, (byte) 0x75, (byte) 0xf3, (byte) 0xbf, + (byte) 0x50, (byte) 0xa1, (byte) 0xbc, (byte) 0x03, (byte) 0x64, (byte) 0x22, + (byte) 0xe6, (byte) 0x1a, (byte) 0xa1, (byte) 0xe1, (byte) 0x06, (byte) 0x68, + (byte) 0x3b, (byte) 0xbc, (byte) 0x9f, (byte) 0xd3, (byte) 0xae, (byte) 0x77, + (byte) 0x5e, (byte) 0x88, (byte) 0x0c, (byte) 0x5e, (byte) 0x0c, (byte) 0xb2, + (byte) 0x38, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, (byte) 0x30, + (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, + (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x2c, + (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, + (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, (byte) 0x04, + (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, (byte) 0x65, + (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, (byte) 0x47, + (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, (byte) 0x74, + (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, (byte) 0x72, + (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61, + (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03, + (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04, + (byte) 0x14, (byte) 0xd5, (byte) 0xc4, (byte) 0x72, (byte) 0xbd, (byte) 0xd2, + (byte) 0x4e, (byte) 0x90, (byte) 0x1b, (byte) 0x14, (byte) 0x32, (byte) 0xdb, + (byte) 0x03, (byte) 0xae, (byte) 0xfa, (byte) 0x27, (byte) 0x7d, (byte) 0x8d, + (byte) 0xe4, (byte) 0x80, (byte) 0x58, (byte) 0x30, (byte) 0x1f, (byte) 0x06, + (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18, + (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x5f, (byte) 0x5b, + (byte) 0x5e, (byte) 0xac, (byte) 0x29, (byte) 0xfa, (byte) 0xa1, (byte) 0x9f, + (byte) 0x9e, (byte) 0xad, (byte) 0x46, (byte) 0xe1, (byte) 0xbc, (byte) 0x20, + (byte) 0x72, (byte) 0xcf, (byte) 0x4a, (byte) 0xd4, (byte) 0xfa, (byte) 0xe3, + (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, + (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, + (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81, + (byte) 0x00, (byte) 0x43, (byte) 0x99, (byte) 0x9f, (byte) 0x67, (byte) 0x08, + (byte) 0x43, (byte) 0xd5, (byte) 0x6b, (byte) 0x6f, (byte) 0xd7, (byte) 0x05, + (byte) 0xd6, (byte) 0x75, (byte) 0x34, (byte) 0x30, (byte) 0xca, (byte) 0x20, + (byte) 0x47, (byte) 0x61, (byte) 0xa1, (byte) 0x89, (byte) 0xb6, (byte) 0xf1, + (byte) 0x49, (byte) 0x7b, (byte) 0xd9, (byte) 0xb9, (byte) 0xe8, (byte) 0x1e, + (byte) 0x29, (byte) 0x74, (byte) 0x0a, (byte) 0x67, (byte) 0xc0, (byte) 0x7d, + (byte) 0xb8, (byte) 0xe6, (byte) 0x39, (byte) 0xa8, (byte) 0x5e, (byte) 0xc3, + (byte) 0xb0, (byte) 0xa1, (byte) 0x30, (byte) 0x6a, (byte) 0x1f, (byte) 0x1d, + (byte) 0xfc, (byte) 0x11, (byte) 0x59, (byte) 0x0b, (byte) 0xb9, (byte) 0xad, + (byte) 0x3a, (byte) 0x4e, (byte) 0x50, (byte) 0x0a, (byte) 0x61, (byte) 0xdb, + (byte) 0x75, (byte) 0x6b, (byte) 0xe5, (byte) 0x3f, (byte) 0x8d, (byte) 0xde, + (byte) 0x28, (byte) 0x68, (byte) 0xb1, (byte) 0x29, (byte) 0x9a, (byte) 0x18, + (byte) 0x8a, (byte) 0xfc, (byte) 0x3f, (byte) 0x13, (byte) 0x93, (byte) 0x29, + (byte) 0xed, (byte) 0x22, (byte) 0x7c, (byte) 0xb4, (byte) 0x50, (byte) 0xd5, + (byte) 0x4d, (byte) 0x32, (byte) 0x4d, (byte) 0x42, (byte) 0x2b, (byte) 0x29, + (byte) 0x97, (byte) 0x86, (byte) 0xc0, (byte) 0x01, (byte) 0x00, (byte) 0x25, + (byte) 0xf6, (byte) 0xd3, (byte) 0x2a, (byte) 0xd8, (byte) 0xda, (byte) 0x13, + (byte) 0x94, (byte) 0x12, (byte) 0x78, (byte) 0x14, (byte) 0x0b, (byte) 0x51, + (byte) 0xc0, (byte) 0x45, (byte) 0xb4, (byte) 0x02, (byte) 0x37, (byte) 0x98, + (byte) 0x42, (byte) 0x3c, (byte) 0xcb, (byte) 0x2e, (byte) 0xe4, (byte) 0x38, + (byte) 0x69, (byte) 0x1b, (byte) 0x72, (byte) 0xf0, (byte) 0xaa, (byte) 0x89, + (byte) 0x7e, (byte) 0xde, (byte) 0xb2 + }; + + /** + * The amount of time to allow before and after expected time for variance + * in timing tests. + */ + private static final long SLOP_TIME_MILLIS = 15000L; + + @Override + protected void setUp() throws Exception { + mAndroidKeyStore = android.security.KeyStore.getInstance(); + + assertTrue(mAndroidKeyStore.reset()); + assertFalse(mAndroidKeyStore.isUnlocked()); + + mKeyStore = java.security.KeyStore.getInstance("AndroidKeyStore"); + } + + private void setupPassword() { + assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111")); + assertTrue(mAndroidKeyStore.isUnlocked()); + + assertEquals(0, mAndroidKeyStore.list("").length); + } + + private void assertAliases(final String[] expectedAliases) throws KeyStoreException { + final Enumeration<String> aliases = mKeyStore.aliases(); + int count = 0; + + final Set<String> expectedSet = new HashSet<String>(); + expectedSet.addAll(Arrays.asList(expectedAliases)); + + while (aliases.hasMoreElements()) { + count++; + final String alias = aliases.nextElement(); + assertTrue("The alias should be in the expected set", expectedSet.contains(alias)); + expectedSet.remove(alias); + } + assertTrue("The expected set and actual set should be exactly equal", expectedSet.isEmpty()); + assertEquals("There should be the correct number of keystore entries", + expectedAliases.length, count); + } + + public void testKeyStore_Aliases_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertAliases(new String[] {}); + + assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, + null)); + + assertAliases(new String[] { TEST_ALIAS_1 }); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 }); + } + + public void testKeyStore_Aliases_NotInitialized_Encrypted_Failure() throws Exception { + setupPassword(); + + try { + mKeyStore.aliases(); + fail("KeyStore should throw exception when not initialized"); + } catch (KeyStoreException success) { + } + } + + public void testKeyStore_ContainsAliases_PrivateAndCA_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertAliases(new String[] {}); + + assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, + null)); + + assertTrue("Should contain generated private key", mKeyStore.containsAlias(TEST_ALIAS_1)); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2)); + + assertFalse("Should not contain unadded certificate alias", + mKeyStore.containsAlias(TEST_ALIAS_3)); + } + + public void testKeyStore_ContainsAliases_CAOnly_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2)); + } + + public void testKeyStore_ContainsAliases_NonExistent_Encrypted_Failure() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertFalse("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_1)); + } + + public void testKeyStore_DeleteEntry_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + // TEST_ALIAS_1 + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + // TEST_ALIAS_2 + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + // TEST_ALIAS_3 + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_3, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 }); + + mKeyStore.deleteEntry(TEST_ALIAS_1); + + assertAliases(new String[] { TEST_ALIAS_2, TEST_ALIAS_3 }); + + mKeyStore.deleteEntry(TEST_ALIAS_3); + + assertAliases(new String[] { TEST_ALIAS_2 }); + + mKeyStore.deleteEntry(TEST_ALIAS_2); + + assertAliases(new String[] { }); + } + + public void testKeyStore_DeleteEntry_EmptyStore_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + // Should not throw when a non-existent entry is requested for delete. + mKeyStore.deleteEntry(TEST_ALIAS_1); + } + + public void testKeyStore_DeleteEntry_NonExistent_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + // TEST_ALIAS_1 + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + // Should not throw when a non-existent entry is requested for delete. + mKeyStore.deleteEntry(TEST_ALIAS_2); + } + + public void testKeyStore_GetCertificate_Single_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertAliases(new String[] { TEST_ALIAS_1 }); + + assertNull("Certificate should not exist in keystore", + mKeyStore.getCertificate(TEST_ALIAS_2)); + + Certificate retrieved = mKeyStore.getCertificate(TEST_ALIAS_1); + + assertNotNull("Retrieved certificate should not be null", retrieved); + + CertificateFactory f = CertificateFactory.getInstance("X.509"); + Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + assertEquals("Actual and retrieved certificates should be the same", actual, retrieved); + } + + public void testKeyStore_GetCertificate_NonExist_Encrypted_Failure() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertNull("Certificate should not exist in keystore", + mKeyStore.getCertificate(TEST_ALIAS_1)); + } + + public void testKeyStore_GetCertificateAlias_CAEntry_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + CertificateFactory f = CertificateFactory.getInstance("X.509"); + Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + assertEquals("Stored certificate alias should be found", TEST_ALIAS_1, + mKeyStore.getCertificateAlias(actual)); + } + + public void testKeyStore_GetCertificateAlias_PrivateKeyEntry_Encrypted_Success() + throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + CertificateFactory f = CertificateFactory.getInstance("X.509"); + Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + + assertEquals("Stored certificate alias should be found", TEST_ALIAS_1, + mKeyStore.getCertificateAlias(actual)); + } + + public void testKeyStore_GetCertificateAlias_CAEntry_WithPrivateKeyUsingCA_Encrypted_Success() + throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + // Insert TrustedCertificateEntry with CA name + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + // Insert PrivateKeyEntry that uses the same CA + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + CertificateFactory f = CertificateFactory.getInstance("X.509"); + Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + assertEquals("Stored certificate alias should be found", TEST_ALIAS_2, + mKeyStore.getCertificateAlias(actual)); + } + + public void testKeyStore_GetCertificateAlias_NonExist_Empty_Encrypted_Failure() + throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + CertificateFactory f = CertificateFactory.getInstance("X.509"); + Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + assertNull("Stored certificate alias should not be found", + mKeyStore.getCertificateAlias(actual)); + } + + public void testKeyStore_GetCertificateAlias_NonExist_Encrypted_Failure() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + CertificateFactory f = CertificateFactory.getInstance("X.509"); + Certificate userCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + + assertNull("Stored certificate alias should be found", + mKeyStore.getCertificateAlias(userCert)); + } + + public void testKeyStore_GetCertificateChain_SingleLength_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + Certificate[] expected = new Certificate[2]; + expected[0] = cf.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expected[1] = cf.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + Certificate[] actual = mKeyStore.getCertificateChain(TEST_ALIAS_1); + + assertNotNull("Returned certificate chain should not be null", actual); + assertEquals("Returned certificate chain should be correct size", expected.length, + actual.length); + assertEquals("First certificate should be user certificate", expected[0], actual[0]); + assertEquals("Second certificate should be CA certificate", expected[1], actual[1]); + + // Negative test when keystore is populated. + assertNull("Stored certificate alias should not be found", + mKeyStore.getCertificateChain(TEST_ALIAS_2)); + } + + public void testKeyStore_GetCertificateChain_NonExist_Encrypted_Failure() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertNull("Stored certificate alias should not be found", + mKeyStore.getCertificateChain(TEST_ALIAS_1)); + } + + public void testKeyStore_GetCreationDate_PrivateKeyEntry_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + Date now = new Date(); + Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1); + + Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS); + Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS); + + assertTrue("Time should be close to current time", actual.before(expectedBefore)); + assertTrue("Time should be close to current time", actual.after(expectedAfter)); + } + + public void testKeyStore_GetCreationDate_PrivateKeyEntry_Unencrypted_Success() throws Exception { + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + + Date now = new Date(); + Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1); + + Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS); + Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS); + + assertTrue("Time should be close to current time", actual.before(expectedBefore)); + assertTrue("Time should be close to current time", actual.after(expectedAfter)); + } + + public void testKeyStore_GetCreationDate_CAEntry_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + Date now = new Date(); + Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1); + assertNotNull("Certificate should be found", actual); + + Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS); + Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS); + + assertTrue("Time should be close to current time", actual.before(expectedBefore)); + assertTrue("Time should be close to current time", actual.after(expectedAfter)); + } + + public void testKeyStore_GetEntry_NullParams_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Entry should exist", entry); + + assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry); + + PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry; + + assertPrivateKeyEntryEquals(keyEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + + public void testKeyStore_GetEntry_EC_NullParams_Unencrypted_Success() throws Exception { + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_EC_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, + FAKE_EC_USER_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_EC_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + + Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Entry should exist", entry); + + assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry); + + PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry; + + assertPrivateKeyEntryEquals(keyEntry, "EC", FAKE_EC_KEY_1, FAKE_EC_USER_1, FAKE_EC_CA_1); + } + + public void testKeyStore_GetEntry_RSA_NullParams_Unencrypted_Success() throws Exception { + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, + FAKE_RSA_USER_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + + Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Entry should exist", entry); + + assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry); + + PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry; + + assertPrivateKeyEntryEquals(keyEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + + @SuppressWarnings("unchecked") + private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, String keyType, byte[] key, + byte[] cert, byte[] ca) throws Exception { + KeyFactory keyFact = KeyFactory.getInstance(keyType); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(key)); + + CertificateFactory certFact = CertificateFactory.getInstance("X.509"); + Certificate expectedCert = certFact.generateCertificate(new ByteArrayInputStream(cert)); + + final Collection<Certificate> expectedChain; + if (ca != null) { + expectedChain = (Collection<Certificate>) certFact + .generateCertificates(new ByteArrayInputStream(ca)); + } else { + expectedChain = null; + } + + assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, expectedChain); + } + + private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey, + Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception { + if (expectedKey instanceof ECKey) { + assertEquals("Returned PrivateKey should be what we inserted", + ((ECKey) expectedKey).getParams().getCurve(), + ((ECKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve()); + } else if (expectedKey instanceof RSAKey) { + assertEquals("Returned PrivateKey should be what we inserted", + ((RSAKey) expectedKey).getModulus(), + ((RSAKey) keyEntry.getPrivateKey()).getModulus()); + } + + assertEquals("Returned Certificate should be what we inserted", expectedCert, + keyEntry.getCertificate()); + + Certificate[] actualChain = keyEntry.getCertificateChain(); + + assertEquals("First certificate in chain should be user cert", expectedCert, actualChain[0]); + + if (expectedChain == null) { + assertEquals("Certificate chain should not include CAs", 1, actualChain.length); + } else { + int i = 1; + final Iterator<Certificate> it = expectedChain.iterator(); + while (it.hasNext()) { + assertEquals("CA chain certificate should equal what we put in", it.next(), + actualChain[i++]); + } + } + } + + public void testKeyStore_GetEntry_Nonexistent_NullParams_Encrypted_Failure() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertNull("A non-existent entry should return null", + mKeyStore.getEntry(TEST_ALIAS_1, null)); + } + + public void testKeyStore_GetEntry_Nonexistent_NullParams_Unencrypted_Failure() throws Exception { + mKeyStore.load(null, null); + + assertNull("A non-existent entry should return null", + mKeyStore.getEntry(TEST_ALIAS_1, null)); + } + + public void testKeyStore_GetKey_NoPassword_Encrypted_Success() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + Key key = mKeyStore.getKey(TEST_ALIAS_1, null); + assertNotNull("Key should exist", key); + + assertTrue("Should be a PrivateKey", key instanceof PrivateKey); + assertTrue("Should be a RSAKey", key instanceof RSAKey); + + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + + assertEquals("Inserted key should be same as retrieved key", + ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus()); + } + + public void testKeyStore_GetKey_NoPassword_Unencrypted_Success() throws Exception { + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_NONE)); + + Key key = mKeyStore.getKey(TEST_ALIAS_1, null); + assertNotNull("Key should exist", key); + + assertTrue("Should be a PrivateKey", key instanceof PrivateKey); + assertTrue("Should be a RSAKey", key instanceof RSAKey); + + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + + assertEquals("Inserted key should be same as retrieved key", + ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus()); + } + + public void testKeyStore_GetKey_Certificate_Encrypted_Failure() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertNull("Certificate entries should return null", mKeyStore.getKey(TEST_ALIAS_1, null)); + } + + public void testKeyStore_GetKey_NonExistent_Encrypted_Failure() throws Exception { + setupPassword(); + + mKeyStore.load(null, null); + + assertNull("A non-existent entry should return null", mKeyStore.getKey(TEST_ALIAS_1, null)); + } + + public void testKeyStore_GetProvider_Encrypted_Success() throws Exception { + assertEquals(AndroidKeyStoreProvider.PROVIDER_NAME, mKeyStore.getProvider().getName()); + setupPassword(); + assertEquals(AndroidKeyStoreProvider.PROVIDER_NAME, mKeyStore.getProvider().getName()); + } + + public void testKeyStore_GetType_Encrypted_Success() throws Exception { + assertEquals(AndroidKeyStoreSpi.NAME, mKeyStore.getType()); + setupPassword(); + assertEquals(AndroidKeyStoreSpi.NAME, mKeyStore.getType()); + } + + public void testKeyStore_IsCertificateEntry_CA_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertTrue("Should return true for CA certificate", + mKeyStore.isCertificateEntry(TEST_ALIAS_1)); + } + + public void testKeyStore_IsCertificateEntry_PrivateKey_Encrypted_Failure() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertFalse("Should return false for PrivateKeyEntry", + mKeyStore.isCertificateEntry(TEST_ALIAS_1)); + } + + public void testKeyStore_IsCertificateEntry_NonExist_Encrypted_Failure() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertFalse("Should return false for non-existent entry", + mKeyStore.isCertificateEntry(TEST_ALIAS_1)); + } + + public void testKeyStore_IsCertificateEntry_NonExist_Unencrypted_Failure() throws Exception { + mKeyStore.load(null, null); + + assertFalse("Should return false for non-existent entry", + mKeyStore.isCertificateEntry(TEST_ALIAS_1)); + } + + public void testKeyStore_IsKeyEntry_PrivateKey_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertTrue("Should return true for PrivateKeyEntry", mKeyStore.isKeyEntry(TEST_ALIAS_1)); + } + + public void testKeyStore_IsKeyEntry_CA_Encrypted_Failure() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertFalse("Should return false for CA certificate", mKeyStore.isKeyEntry(TEST_ALIAS_1)); + } + + public void testKeyStore_IsKeyEntry_NonExist_Encrypted_Failure() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertFalse("Should return false for non-existent entry", + mKeyStore.isKeyEntry(TEST_ALIAS_1)); + } + + public void testKeyStore_SetCertificate_CA_Encrypted_Success() throws Exception { + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + final Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + setupPassword(); + mKeyStore.load(null, null); + + mKeyStore.setCertificateEntry(TEST_ALIAS_1, actual); + assertAliases(new String[] { TEST_ALIAS_1 }); + + Certificate retrieved = mKeyStore.getCertificate(TEST_ALIAS_1); + + assertEquals("Retrieved certificate should be the same as the one inserted", actual, + retrieved); + } + + public void testKeyStore_SetCertificate_CAExists_Overwrite_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertAliases(new String[] { TEST_ALIAS_1 }); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + final Certificate cert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + // TODO have separate FAKE_CA for second test + mKeyStore.setCertificateEntry(TEST_ALIAS_1, cert); + + assertAliases(new String[] { TEST_ALIAS_1 }); + } + + public void testKeyStore_SetCertificate_PrivateKeyExists_Encrypted_Failure() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1, + FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertAliases(new String[] { TEST_ALIAS_1 }); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + final Certificate cert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + try { + mKeyStore.setCertificateEntry(TEST_ALIAS_1, cert); + fail("Should throw when trying to overwrite a PrivateKey entry with a Certificate"); + } catch (KeyStoreException success) { + } + } + + public void testKeyStore_SetEntry_PrivateKeyEntry_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expected, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry; + + assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, FAKE_RSA_CA_1); + } + + public void testKeyStore_SetEntry_PrivateKeyEntry_EC_Unencrypted_Success() throws Exception { + mKeyStore.load(null, null); + + KeyFactory keyFact = KeyFactory.getInstance("EC"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_EC_KEY_1)); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_EC_USER_1)); + expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_EC_CA_1)); + + PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expected, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry; + + assertPrivateKeyEntryEquals(actual, "EC", FAKE_EC_KEY_1, FAKE_EC_USER_1, FAKE_EC_CA_1); + } + + public void testKeyStore_SetEntry_PrivateKeyEntry_RSA_Unencrypted_Success() throws Exception { + mKeyStore.load(null, null); + + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expected, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry; + + assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, FAKE_RSA_CA_1); + } + + public void testKeyStore_SetEntry_PrivateKeyEntry_Params_Unencrypted_Failure() throws Exception { + mKeyStore.load(null, null); + + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + PrivateKeyEntry entry = new PrivateKeyEntry(expectedKey, expectedChain); + + try { + mKeyStore.setEntry(TEST_ALIAS_1, entry, + new KeyStoreParameter.Builder(getContext()) + .setEncryptionRequired(true) + .build()); + fail("Shouldn't be able to insert encrypted entry when KeyStore uninitialized"); + } catch (KeyStoreException expected) { + } + + assertNull(mKeyStore.getEntry(TEST_ALIAS_1, null)); + } + + public void + testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_PrivateKeyEntry_Encrypted_Success() + throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + final KeyFactory keyFact = KeyFactory.getInstance("RSA"); + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + // Start with PrivateKeyEntry + { + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expected, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry; + + assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + + // TODO make entirely new test vector for the overwrite + // Replace with PrivateKeyEntry + { + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expected, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry; + + assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + } + + public void testKeyStore_SetEntry_CAEntry_Overwrites_PrivateKeyEntry_Encrypted_Success() + throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + // Start with TrustedCertificateEntry + { + final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert); + mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + assertTrue("Retrieved entry should be of type TrustedCertificateEntry", + actualEntry instanceof TrustedCertificateEntry); + TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry; + assertEquals("Stored and retrieved certificates should be the same", + expectedCertEntry.getTrustedCertificate(), + actualCertEntry.getTrustedCertificate()); + } + + // Replace with PrivateKeyEntry + { + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry; + assertPrivateKeyEntryEquals(actualPrivEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + } + + public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_CAEntry_Encrypted_Success() + throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + // Start with PrivateKeyEntry + { + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expectedChain[1] = caCert; + + PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry; + assertPrivateKeyEntryEquals(actualPrivEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + + // Replace with TrustedCertificateEntry + { + TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert); + mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + assertTrue("Retrieved entry should be of type TrustedCertificateEntry", + actualEntry instanceof TrustedCertificateEntry); + TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry; + assertEquals("Stored and retrieved certificates should be the same", + expectedCertEntry.getTrustedCertificate(), + actualCertEntry.getTrustedCertificate()); + } + } + + public + void + testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_ShortPrivateKeyEntry_Encrypted_Success() + throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + // Start with PrivateKeyEntry + { + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + final Certificate[] expectedChain = new Certificate[2]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + expectedChain[1] = caCert; + + PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry; + assertPrivateKeyEntryEquals(actualPrivEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + + // Replace with PrivateKeyEntry that has no chain + { + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + final Certificate[] expectedChain = new Certificate[1]; + expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + + PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain); + + mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry; + assertPrivateKeyEntryEquals(actualPrivEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + null); + } + } + + public void testKeyStore_SetEntry_CAEntry_Overwrites_CAEntry_Encrypted_Success() + throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + // Insert TrustedCertificateEntry + { + final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert); + mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + assertTrue("Retrieved entry should be of type TrustedCertificateEntry", + actualEntry instanceof TrustedCertificateEntry); + TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry; + assertEquals("Stored and retrieved certificates should be the same", + expectedCertEntry.getTrustedCertificate(), + actualCertEntry.getTrustedCertificate()); + } + + // Replace with TrustedCertificateEntry of USER + { + final Certificate userCert = f + .generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + + TrustedCertificateEntry expectedUserEntry = new TrustedCertificateEntry(userCert); + mKeyStore.setEntry(TEST_ALIAS_1, expectedUserEntry, null); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + assertTrue("Retrieved entry should be of type TrustedCertificateEntry", + actualEntry instanceof TrustedCertificateEntry); + TrustedCertificateEntry actualUserEntry = (TrustedCertificateEntry) actualEntry; + assertEquals("Stored and retrieved certificates should be the same", + expectedUserEntry.getTrustedCertificate(), + actualUserEntry.getTrustedCertificate()); + } + } + + public void testKeyStore_SetKeyEntry_ProtectedKey_Encrypted_Failure() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + final Certificate[] chain = new Certificate[2]; + chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + chain[1] = caCert; + + try { + mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, "foo".toCharArray(), chain); + fail("Should fail when a password is specified"); + } catch (KeyStoreException success) { + } + } + + public void testKeyStore_SetKeyEntry_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + final Certificate[] chain = new Certificate[2]; + chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + chain[1] = caCert; + + mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry; + + assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, FAKE_RSA_CA_1); + } + + public void testKeyStore_SetKeyEntry_Replaced_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + final CertificateFactory f = CertificateFactory.getInstance("X.509"); + + final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1)); + + // Insert initial key + { + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + final Certificate[] chain = new Certificate[2]; + chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + chain[1] = caCert; + + mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry; + + assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + + // TODO make a separate key + // Replace key + { + KeyFactory keyFact = KeyFactory.getInstance("RSA"); + PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1)); + final Certificate[] chain = new Certificate[2]; + chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1)); + chain[1] = caCert; + + mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain); + + Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull("Retrieved entry should exist", actualEntry); + + assertTrue("Retrieved entry should be of type PrivateKeyEntry", + actualEntry instanceof PrivateKeyEntry); + + PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry; + + assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, + FAKE_RSA_CA_1); + } + } + + @SuppressWarnings("deprecation") + private static X509Certificate generateCertificate(android.security.KeyStore keyStore, + String alias, BigInteger serialNumber, X500Principal subjectDN, Date notBefore, + Date notAfter) throws Exception { + final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias; + + KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore( + keyStore, privateKeyAlias, KeyStore.UID_SELF); + + final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); + certGen.setPublicKey(keyPair.getPublic()); + certGen.setSerialNumber(serialNumber); + certGen.setSubjectDN(subjectDN); + certGen.setIssuerDN(subjectDN); + certGen.setNotBefore(notBefore); + certGen.setNotAfter(notAfter); + certGen.setSignatureAlgorithm("sha1WithRSA"); + + final X509Certificate cert = certGen.generate(keyPair.getPrivate()); + + return cert; + } + + public void testKeyStore_SetKeyEntry_ReplacedChain_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + // Create key #1 + { + final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1; + assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, + NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); + + Key key = mKeyStore.getKey(TEST_ALIAS_1, null); + + assertTrue(key instanceof PrivateKey); + + PrivateKey expectedKey = (PrivateKey) key; + + X509Certificate expectedCert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, + TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS); + + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, + expectedCert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null); + + assertTrue(entry instanceof PrivateKeyEntry); + + PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry; + + assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, null); + } + + // Replace key #1 with new chain + { + Key key = mKeyStore.getKey(TEST_ALIAS_1, null); + + assertTrue(key instanceof PrivateKey); + + PrivateKey expectedKey = (PrivateKey) key; + + X509Certificate expectedCert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, + TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS); + + mKeyStore.setKeyEntry(TEST_ALIAS_1, expectedKey, null, + new Certificate[] { expectedCert }); + + Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null); + + assertTrue(entry instanceof PrivateKeyEntry); + + PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry; + + assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, null); + } + } + + public void testKeyStore_SetKeyEntry_ReplacedChain_DifferentPrivateKey_Encrypted_Failure() + throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + // Create key #1 + { + final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1; + assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, + NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); + + X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, + TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS); + + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, + cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + } + + // Create key #2 + { + final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_2; + assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, + NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null)); + + X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2, + TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS); + + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_2, + cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + } + + // Replace key #1 with key #2 + { + Key key1 = mKeyStore.getKey(TEST_ALIAS_2, null); + + X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2, + TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS); + + try { + mKeyStore.setKeyEntry(TEST_ALIAS_1, key1, null, new Certificate[] { cert }); + fail("Should not allow setting of KeyEntry with wrong PrivaetKey"); + } catch (KeyStoreException success) { + } + } + } + + public void testKeyStore_SetKeyEntry_ReplacedChain_UnencryptedToEncrypted_Failure() + throws Exception { + mKeyStore.load(null, null); + + // Create key #1 + { + final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1; + assertTrue(mAndroidKeyStore.generate(privateKeyAlias, + android.security.KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, + android.security.KeyStore.FLAG_NONE, null)); + + X509Certificate cert = + generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1, TEST_DN_1, + NOW, NOW_PLUS_10_YEARS); + + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, + cert.getEncoded(), android.security.KeyStore.UID_SELF, + android.security.KeyStore.FLAG_NONE)); + } + + // Replace with one that requires encryption + { + Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null); + + try { + mKeyStore.setEntry(TEST_ALIAS_1, entry, + new KeyStoreParameter.Builder(getContext()) + .setEncryptionRequired(true) + .build()); + fail("Should not allow setting of Entry without unlocked keystore"); + } catch (KeyStoreException success) { + } + + assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111")); + assertTrue(mAndroidKeyStore.isUnlocked()); + + mKeyStore.setEntry(TEST_ALIAS_1, entry, + new KeyStoreParameter.Builder(getContext()) + .setEncryptionRequired(true) + .build()); + } + } + + public void testKeyStore_Size_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertEquals("The keystore size should match expected", 1, mKeyStore.size()); + assertAliases(new String[] { TEST_ALIAS_1 }); + + assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1, + KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + + assertEquals("The keystore size should match expected", 2, mKeyStore.size()); + assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 }); + + assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3, + KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, + null)); + + assertEquals("The keystore size should match expected", 3, mKeyStore.size()); + assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 }); + + assertTrue(mAndroidKeyStore.delete(Credentials.CA_CERTIFICATE + TEST_ALIAS_1)); + + assertEquals("The keystore size should match expected", 2, mKeyStore.size()); + assertAliases(new String[] { TEST_ALIAS_2, TEST_ALIAS_3 }); + + assertTrue(mAndroidKeyStore.delete(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3)); + + assertEquals("The keystore size should match expected", 1, mKeyStore.size()); + assertAliases(new String[] { TEST_ALIAS_2 }); + } + + public void testKeyStore_Store_LoadStoreParam_Encrypted_Failure() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + try { + mKeyStore.store(null); + fail("Should throw UnsupportedOperationException when trying to store"); + } catch (UnsupportedOperationException success) { + } + } + + public void testKeyStore_Load_InputStreamSupplied_Encrypted_Failure() throws Exception { + byte[] buf = "FAKE KEYSTORE".getBytes(); + ByteArrayInputStream is = new ByteArrayInputStream(buf); + + try { + mKeyStore.load(is, null); + fail("Should throw IllegalArgumentException when InputStream is supplied"); + } catch (IllegalArgumentException success) { + } + } + + public void testKeyStore_Load_PasswordSupplied_Encrypted_Failure() throws Exception { + try { + mKeyStore.load(null, "password".toCharArray()); + fail("Should throw IllegalArgumentException when password is supplied"); + } catch (IllegalArgumentException success) { + } + } + + public void testKeyStore_Store_OutputStream_Encrypted_Failure() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + OutputStream sink = new ByteArrayOutputStream(); + try { + mKeyStore.store(sink, null); + fail("Should throw UnsupportedOperationException when trying to store"); + } catch (UnsupportedOperationException success) { + } + + try { + mKeyStore.store(sink, "blah".toCharArray()); + fail("Should throw UnsupportedOperationException when trying to store"); + } catch (UnsupportedOperationException success) { + } + } + + private void setupKey() throws Exception { + final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1; + assertTrue(mAndroidKeyStore + .generate(privateKeyAlias, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, + KeyStore.FLAG_ENCRYPTED, null)); + + X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1, + TEST_DN_1, NOW, NOW_PLUS_10_YEARS); + + assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, + cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED)); + } + + public void testKeyStore_KeyOperations_Wrap_Encrypted_Success() throws Exception { + setupPassword(); + mKeyStore.load(null, null); + + setupKey(); + + // Test key usage + Entry e = mKeyStore.getEntry(TEST_ALIAS_1, null); + assertNotNull(e); + assertTrue(e instanceof PrivateKeyEntry); + + PrivateKeyEntry privEntry = (PrivateKeyEntry) e; + PrivateKey privKey = privEntry.getPrivateKey(); + assertNotNull(privKey); + + PublicKey pubKey = privEntry.getCertificate().getPublicKey(); + + Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + c.init(Cipher.WRAP_MODE, pubKey); + + byte[] expectedKey = new byte[] { + 0x00, 0x05, (byte) 0xAA, (byte) 0x0A5, (byte) 0xFF, 0x55, 0x0A + }; + + SecretKey expectedSecret = new SecretKeySpec(expectedKey, "AES"); + + byte[] wrappedExpected = c.wrap(expectedSecret); + + c.init(Cipher.UNWRAP_MODE, privKey); + SecretKey actualSecret = (SecretKey) c.unwrap(wrappedExpected, "AES", Cipher.SECRET_KEY); + + assertEquals(Arrays.toString(expectedSecret.getEncoded()), + Arrays.toString(actualSecret.getEncoded())); + } +} |