Merge "Pass all offload-exempt prefixes into OffloadController" into oc-dr1-dev
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index 0b1569c..b56437e 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -20,7 +20,6 @@
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 @@
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/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 0122338..3dfd680 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -118,6 +118,18 @@
}
/**
+ * Show the second layer on top of the first layer immediately
+ *
+ * @hide
+ */
+ public void showSecondLayer() {
+ mAlpha = 255;
+ mReverse = false;
+ mTransitionState = TRANSITION_NONE;
+ invalidateSelf();
+ }
+
+ /**
* Show only the first layer.
*/
public void resetTransition() {
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
new file mode 100644
index 0000000..a740b13
--- /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 0000000..415442f
--- /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 0000000..bc8dd13
--- /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 0000000..319cf32
--- /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 0000000..ecf7cbc
--- /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 0000000..1af0b7d
--- /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 0000000..aa718dc
--- /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()));
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 610eaff..9981972 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -191,10 +191,10 @@
case DOZE:
case DOZE_AOD:
mDozeSensors.setProxListening(newState != DozeMachine.State.DOZE);
- mDozeSensors.setListening(true);
if (oldState != DozeMachine.State.INITIALIZED) {
mDozeSensors.reregisterAllSensors();
}
+ mDozeSensors.setListening(true);
break;
case DOZE_AOD_PAUSED:
case DOZE_AOD_PAUSING:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
index a318efc..c454048 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java
@@ -100,4 +100,8 @@
mAnimator = null;
};
};
+
+ public void showBackground() {
+ mBackground.showSecondLayer();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index bb36725..dc81772 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -94,6 +94,13 @@
if (savedInstanceState != null) {
setExpanded(savedInstanceState.getBoolean(EXTRA_EXPANDED));
setListening(savedInstanceState.getBoolean(EXTRA_LISTENING));
+ int[] loc = new int[2];
+ View edit = view.findViewById(android.R.id.edit);
+ edit.getLocationInWindow(loc);
+ int x = loc[0] + edit.getWidth() / 2;
+ int y = loc[1] + edit.getHeight() / 2;
+ mQSCustomizer.setEditLocation(x, y);
+ mQSCustomizer.restoreInstanceState(savedInstanceState);
}
}
@@ -110,6 +117,7 @@
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_EXPANDED, mQsExpanded);
outState.putBoolean(EXTRA_LISTENING, mListening);
+ mQSCustomizer.saveInstanceState(outState);
}
@VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 30053e3..6c95a80 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -20,6 +20,9 @@
import android.animation.AnimatorListenerAdapter;
import android.content.Context;
import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.TransitionDrawable;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.v7.widget.DefaultItemAnimator;
@@ -42,6 +45,7 @@
import com.android.systemui.R;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.qs.QSContainerImpl;
import com.android.systemui.qs.QSDetailClipper;
import com.android.systemui.qs.QSTileHost;
import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -60,6 +64,7 @@
public class QSCustomizer extends LinearLayout implements OnMenuItemClickListener {
private static final int MENU_RESET = Menu.FIRST;
+ private static final String EXTRA_QS_CUSTOMIZING = "qs_customizing";
private final QSDetailClipper mClipper;
@@ -109,11 +114,16 @@
DefaultItemAnimator animator = new DefaultItemAnimator();
animator.setMoveDuration(TileAdapter.MOVE_DURATION);
mRecyclerView.setItemAnimator(animator);
+ updateNavBackDrop(getResources().getConfiguration());
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ updateNavBackDrop(newConfig);
+ }
+
+ private void updateNavBackDrop(Configuration newConfig) {
View navBackdrop = findViewById(R.id.nav_bar_background);
if (navBackdrop != null) {
boolean shouldShow = newConfig.smallestScreenWidthDp >= 600
@@ -154,6 +164,21 @@
}
}
+
+ public void showImmediately() {
+ if (!isShown) {
+ setVisibility(VISIBLE);
+ mClipper.showBackground();
+ isShown = true;
+ setTileSpecs();
+ setCustomizing(true);
+ queryTiles();
+ mNotifQsContainer.setCustomizerAnimating(false);
+ mNotifQsContainer.setCustomizerShowing(true);
+ Dependency.get(KeyguardMonitor.class).addCallback(mKeyguardCallback);
+ }
+ }
+
private void queryTiles() {
mFinishedFetchingTiles = false;
Runnable tileQueryFetchCompletion = () -> {
@@ -227,6 +252,35 @@
}
}
+
+ public void saveInstanceState(Bundle outState) {
+ if (isShown) {
+ Dependency.get(KeyguardMonitor.class).removeCallback(mKeyguardCallback);
+ }
+ outState.putBoolean(EXTRA_QS_CUSTOMIZING, mCustomizing);
+ }
+
+ public void restoreInstanceState(Bundle savedInstanceState) {
+ boolean customizing = savedInstanceState.getBoolean(EXTRA_QS_CUSTOMIZING);
+ if (customizing) {
+ setVisibility(VISIBLE);
+ addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ removeOnLayoutChangeListener(this);
+ showImmediately();
+ }
+ });
+ }
+ }
+
+ public void setEditLocation(int x, int y) {
+ mX = x;
+ mY = y;
+ }
+
private final Callback mKeyguardCallback = () -> {
if (!isAttachedToWindow()) return;
if (Dependency.get(KeyguardMonitor.class).isShowing() && !mOpening) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index c891418..92f26d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -116,7 +116,7 @@
}
@Override
- protected boolean transformScale() {
+ protected boolean transformScale(TransformState otherState) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
index fb4e2ec..c4aabe4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.notification;
import android.text.Layout;
+import android.text.Spanned;
import android.text.TextUtils;
import android.util.Pools;
import android.view.View;
@@ -50,12 +51,69 @@
int ownEllipsized = getEllipsisCount();
int otherEllipsized = otherTvs.getEllipsisCount();
return ownEllipsized == otherEllipsized
- && getInnerHeight(mText) == getInnerHeight(otherTvs.mText);
+ && mText.getLineCount() == otherTvs.mText.getLineCount()
+ && hasSameSpans(otherTvs);
}
}
return false;
}
+ private boolean hasSameSpans(TextViewTransformState otherTvs) {
+ boolean hasSpans = mText instanceof Spanned;
+ boolean otherHasSpans = otherTvs.mText instanceof Spanned;
+ if (hasSpans != otherHasSpans) {
+ return false;
+ } else if (!hasSpans) {
+ return true;
+ }
+ // Actually both have spans, let's try to compare them
+ Spanned ownSpanned = (Spanned) mText;
+ Object[] spans = ownSpanned.getSpans(0, ownSpanned.length(), Object.class);
+ Spanned otherSpanned = (Spanned) otherTvs.mText;
+ Object[] otherSpans = otherSpanned.getSpans(0, otherSpanned.length(), Object.class);
+ if (spans.length != otherSpans.length) {
+ return false;
+ }
+ for (int i = 0; i < spans.length; i++) {
+ Object span = spans[i];
+ Object otherSpan = otherSpans[i];
+ if (!span.getClass().equals(otherSpan.getClass())) {
+ return false;
+ }
+ if (ownSpanned.getSpanStart(span) != otherSpanned.getSpanStart(otherSpan)
+ || ownSpanned.getSpanEnd(span) != otherSpanned.getSpanEnd(otherSpan)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ protected boolean transformScale(TransformState otherState) {
+ if (!(otherState instanceof TextViewTransformState)) {
+ return false;
+ }
+ TextViewTransformState otherTvs = (TextViewTransformState) otherState;
+ int lineCount = mText.getLineCount();
+ return lineCount == 1 && lineCount == otherTvs.mText.getLineCount()
+ && getEllipsisCount() == otherTvs.getEllipsisCount()
+ && getViewHeight() != otherTvs.getViewHeight();
+ }
+
+ @Override
+ protected int getViewWidth() {
+ Layout l = mText.getLayout();
+ if (l != null) {
+ return (int) l.getLineWidth(0);
+ }
+ return super.getViewWidth();
+ }
+
+ @Override
+ protected int getViewHeight() {
+ return mText.getLineHeight();
+ }
+
private int getInnerHeight(TextView text) {
return text.getHeight() - text.getPaddingTop() - text.getPaddingBottom();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index a77dd4e..bafedff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -108,7 +108,7 @@
final View transformedView = mTransformedView;
boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
- boolean transformScale = transformScale();
+ boolean transformScale = transformScale(otherState);
// lets animate the positions correctly
if (transformationAmount == 0.0f
|| transformX && getTransformationStartX() == UNDEFINED
@@ -132,16 +132,16 @@
}
// we also want to animate the scale if we're the same
View otherView = otherState.getTransformedView();
- if (transformScale && otherView.getWidth() != transformedView.getWidth()) {
- setTransformationStartScaleX(otherView.getWidth() * otherView.getScaleX()
- / (float) transformedView.getWidth());
+ if (transformScale && otherState.getViewWidth() != getViewWidth()) {
+ setTransformationStartScaleX(otherState.getViewWidth() * otherView.getScaleX()
+ / (float) getViewWidth());
transformedView.setPivotX(0);
} else {
setTransformationStartScaleX(UNDEFINED);
}
- if (transformScale && otherView.getHeight() != transformedView.getHeight()) {
- setTransformationStartScaleY(otherView.getHeight() * otherView.getScaleY()
- / (float) transformedView.getHeight());
+ if (transformScale && otherState.getViewHeight() != getViewHeight()) {
+ setTransformationStartScaleY(otherState.getViewHeight() * otherView.getScaleY()
+ / (float) getViewHeight());
transformedView.setPivotY(0);
} else {
setTransformationStartScaleY(UNDEFINED);
@@ -205,7 +205,15 @@
}
}
- protected boolean transformScale() {
+ protected int getViewWidth() {
+ return mTransformedView.getWidth();
+ }
+
+ protected int getViewHeight() {
+ return mTransformedView.getHeight();
+ }
+
+ protected boolean transformScale(TransformState otherState) {
return false;
}
@@ -259,7 +267,7 @@
final View transformedView = mTransformedView;
boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
- boolean transformScale = transformScale();
+ boolean transformScale = transformScale(otherState);
// lets animate the positions correctly
if (transformationAmount == 0.0f) {
if (transformX) {
@@ -275,13 +283,13 @@
setTransformationStartY(start);
}
View otherView = otherState.getTransformedView();
- if (transformScale && otherView.getWidth() != transformedView.getWidth()) {
+ if (transformScale && otherState.getViewWidth() != getViewWidth()) {
setTransformationStartScaleX(transformedView.getScaleX());
transformedView.setPivotX(0);
} else {
setTransformationStartScaleX(UNDEFINED);
}
- if (transformScale && otherView.getHeight() != transformedView.getHeight()) {
+ if (transformScale && otherState.getViewHeight() != getViewHeight()) {
setTransformationStartScaleY(transformedView.getScaleY());
transformedView.setPivotY(0);
} else {
@@ -333,14 +341,14 @@
if (transformationStartScaleX != UNDEFINED) {
transformedView.setScaleX(
NotificationUtils.interpolate(transformationStartScaleX,
- (otherView.getWidth() / (float) transformedView.getWidth()),
+ (otherState.getViewWidth() / (float) getViewWidth()),
interpolatedValue));
}
float transformationStartScaleY = getTransformationStartScaleY();
if (transformationStartScaleY != UNDEFINED) {
transformedView.setScaleY(
NotificationUtils.interpolate(transformationStartScaleY,
- (otherView.getHeight() / (float) transformedView.getHeight()),
+ (otherState.getViewHeight() / (float) getViewHeight()),
interpolatedValue));
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 33d92fc..bcba789 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -3487,6 +3487,11 @@
pw.print (" ");
mNotificationPanel.dump(fd, pw, args);
}
+ pw.println(" mStackScroller: ");
+ if (mStackScroller != null) {
+ pw.print (" ");
+ mStackScroller.dump(fd, pw, args);
+ }
DozeLog.dump(pw);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 41cde9c..2981b39 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -91,6 +91,8 @@
import android.support.v4.graphics.ColorUtils;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -4257,6 +4259,19 @@
mShelf.setDarkOffsetX(shelfOffsetX);
}
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println(String.format("[%s: pulsing=%s qsCustomizerShowing=%s visibility=%s"
+ + " alpha:%f scrollY:%d]",
+ this.getClass().getSimpleName(),
+ mPulsing != null ?"T":"f",
+ mAmbientState.isQsCustomizerShowing() ? "T":"f",
+ getVisibility() == View.VISIBLE ? "visible"
+ : getVisibility() == View.GONE ? "gone"
+ : "invisible",
+ getAlpha(),
+ mAmbientState.getScrollY()));
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/