diff options
6 files changed, 547 insertions, 0 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 812ac9ec73db..1cd5fa29b1b8 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -109,6 +109,7 @@ import java.util.Map; import java.util.TimeZone; import java.util.regex.Pattern; +import libcore.io.EventLogger; import libcore.io.IoUtils; import dalvik.system.CloseGuard; @@ -4870,6 +4871,13 @@ public final class ActivityThread { } } + private static class EventLoggingReporter implements EventLogger.Reporter { + @Override + public void report (int code, Object... list) { + EventLog.writeEvent(code, list); + } + } + public static void main(String[] args) { SamplingProfilerIntegration.start(); @@ -4880,6 +4888,9 @@ public final class ActivityThread { Environment.initForCurrentUser(); + // Set the reporter for event logging in libcore + EventLogger.setReporter(new EventLoggingReporter()); + Security.addProvider(new AndroidKeyStoreProvider()); Process.setArgV0("<pre-initialized>"); diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 466fd24c39c5..7305d8b496bf 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -2130,6 +2130,12 @@ </intent-filter> </receiver> + <receiver android:name="com.android.server.updates.CertPinInstallReceiver" > + <intent-filter> + <action android:name="android.intent.action.UPDATE_PINS" /> + </intent-filter> + </receiver> + <receiver android:name="com.android.server.MasterClearReceiver" android:permission="android.permission.MASTER_CLEAR" android:priority="100" > diff --git a/services/java/com/android/server/EventLogTags.logtags b/services/java/com/android/server/EventLogTags.logtags index 39355d537cea..840e0067ed56 100644 --- a/services/java/com/android/server/EventLogTags.logtags +++ b/services/java/com/android/server/EventLogTags.logtags @@ -156,3 +156,8 @@ option java_package com.android.server 51200 lockdown_vpn_connecting (egress_net|1) 51201 lockdown_vpn_connected (egress_net|1) 51202 lockdown_vpn_error (egress_net|1) + +# --------------------------- +# ConfigUpdateInstallReceiver.java +# --------------------------- +51300 config_install_failed (dir|3) diff --git a/services/java/com/android/server/updatable/CertPinInstallReceiver.java b/services/java/com/android/server/updatable/CertPinInstallReceiver.java new file mode 100644 index 000000000000..c03fbc3d0aed --- /dev/null +++ b/services/java/com/android/server/updatable/CertPinInstallReceiver.java @@ -0,0 +1,24 @@ +/* + * 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 com.android.server.updates; + +public class CertPinInstallReceiver extends ConfigUpdateInstallReceiver { + + public CertPinInstallReceiver() { + super("/data/misc/keychain/", "pins", "metadata/", "version"); + } +} diff --git a/services/java/com/android/server/updatable/ConfigUpdateInstallReceiver.java b/services/java/com/android/server/updatable/ConfigUpdateInstallReceiver.java new file mode 100644 index 000000000000..c1f45a880b64 --- /dev/null +++ b/services/java/com/android/server/updatable/ConfigUpdateInstallReceiver.java @@ -0,0 +1,258 @@ +/* + * 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 com.android.server.updates; + +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.provider.Settings; +import android.os.FileUtils; +import android.util.Base64; +import android.util.EventLog; +import android.util.Slog; + +import com.android.server.EventLogTags; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; + +import libcore.io.IoUtils; + +public class ConfigUpdateInstallReceiver extends BroadcastReceiver { + + private static final String TAG = "ConfigUpdateInstallReceiver"; + + private static final String EXTRA_CONTENT_PATH = "CONTENT_PATH"; + private static final String EXTRA_REQUIRED_HASH = "REQUIRED_HASH"; + private static final String EXTRA_SIGNATURE = "SIGNATURE"; + private static final String EXTRA_VERSION_NUMBER = "VERSION"; + + private static final String UPDATE_CERTIFICATE_KEY = "config_update_certificate"; + + private final File updateDir; + private final File updateContent; + private final File updateVersion; + + public ConfigUpdateInstallReceiver(String updateDir, String updateContentPath, + String updateMetadataPath, String updateVersionPath) { + this.updateDir = new File(updateDir); + this.updateContent = new File(updateDir, updateContentPath); + File updateMetadataDir = new File(updateDir, updateMetadataPath); + this.updateVersion = new File(updateMetadataDir, updateVersionPath); + } + + @Override + public void onReceive(final Context context, final Intent intent) { + new Thread() { + @Override + public void run() { + try { + // get the certificate from Settings.Secure + X509Certificate cert = getCert(context.getContentResolver()); + // get the content path from the extras + String altContent = getAltContent(intent); + // get the version from the extras + int altVersion = getVersionFromIntent(intent); + // get the previous value from the extras + String altRequiredHash = getRequiredHashFromIntent(intent); + // get the signature from the extras + String altSig = getSignatureFromIntent(intent); + // get the version currently being used + int currentVersion = getCurrentVersion(); + // get the hash of the currently used value + String currentHash = getCurrentHash(getCurrentContent()); + if (!verifyVersion(currentVersion, altVersion)) { + Slog.e(TAG, "New version is not greater than current version, aborting!"); + } else if (!verifyPreviousHash(currentHash, altRequiredHash)) { + Slog.e(TAG, "Current hash did not match required value, aborting!"); + } else if (!verifySignature(altContent, altVersion, altRequiredHash, altSig, + cert)) { + Slog.e(TAG, "Signature did not verify, aborting!"); + } else { + // install the new content + Slog.i(TAG, "Found new update, installing..."); + install(altContent, altVersion); + Slog.i(TAG, "Installation successful"); + } + } catch (Exception e) { + Slog.e(TAG, "Could not update content!", e); + EventLog.writeEvent(EventLogTags.CONFIG_INSTALL_FAILED, + updateDir.toString()); + } + } + }.start(); + } + + private X509Certificate getCert(ContentResolver cr) { + // get the cert from settings + String cert = Settings.Secure.getString(cr, UPDATE_CERTIFICATE_KEY); + // convert it into a real certificate + try { + byte[] derCert = Base64.decode(cert.getBytes(), Base64.DEFAULT); + InputStream istream = new ByteArrayInputStream(derCert); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + return (X509Certificate) cf.generateCertificate(istream); + } catch (CertificateException e) { + throw new IllegalStateException("Got malformed certificate from settings, ignoring", e); + } + } + + private String getContentFromIntent(Intent i) { + String extraValue = i.getStringExtra(EXTRA_CONTENT_PATH); + if (extraValue == null) { + throw new IllegalStateException("Missing required content path, ignoring."); + } + return extraValue; + } + + private int getVersionFromIntent(Intent i) throws NumberFormatException { + String extraValue = i.getStringExtra(EXTRA_VERSION_NUMBER); + if (extraValue == null) { + throw new IllegalStateException("Missing required version number, ignoring."); + } + return Integer.parseInt(extraValue.trim()); + } + + private String getRequiredHashFromIntent(Intent i) { + String extraValue = i.getStringExtra(EXTRA_REQUIRED_HASH); + if (extraValue == null) { + throw new IllegalStateException("Missing required previous hash, ignoring."); + } + return extraValue.trim(); + } + + private String getSignatureFromIntent(Intent i) { + String extraValue = i.getStringExtra(EXTRA_SIGNATURE); + if (extraValue == null) { + throw new IllegalStateException("Missing required signature, ignoring."); + } + return extraValue.trim(); + } + + private int getCurrentVersion() throws NumberFormatException { + try { + String strVersion = IoUtils.readFileAsString(updateVersion.getCanonicalPath()).trim(); + return Integer.parseInt(strVersion); + } catch (IOException e) { + Slog.i(TAG, "Couldn't find current metadata, assuming first update", e); + return 0; + } + } + + private String getAltContent(Intent i) throws IOException { + String contents = IoUtils.readFileAsString(getContentFromIntent(i)); + return contents.trim(); + } + + private String getCurrentContent() { + try { + return IoUtils.readFileAsString(updateContent.getCanonicalPath()).trim(); + } catch (IOException e) { + Slog.i(TAG, "Failed to read current content, assuming first update!", e); + return null; + } + } + + private static String getCurrentHash(String content) { + if (content == null) { + return "0"; + } + try { + MessageDigest dgst = MessageDigest.getInstance("SHA512"); + byte[] encoded = content.getBytes(); + byte[] fingerprint = dgst.digest(encoded); + return IntegralToString.bytesToHexString(fingerprint, false); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError(e); + } + } + + private boolean verifyVersion(int current, int alternative) { + return (current < alternative); + } + + private boolean verifyPreviousHash(String current, String required) { + // this is an optional value- if the required field is NONE then we ignore it + if (required.equals("NONE")) { + return true; + } + // otherwise, verify that we match correctly + return current.equals(required); + } + + private boolean verifySignature(String content, int version, String requiredPrevious, + String signature, X509Certificate cert) throws Exception { + Signature signer = Signature.getInstance("SHA512withRSA"); + signer.initVerify(cert); + signer.update(content.getBytes()); + signer.update(Long.toString(version).getBytes()); + signer.update(requiredPrevious.getBytes()); + return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT)); + } + + private void writeUpdate(File dir, File file, String content) { + FileOutputStream out = null; + File tmp = null; + try { + // create the temporary file + tmp = File.createTempFile("journal", "", dir); + // create the parents for the destination file + File parent = file.getParentFile(); + parent.mkdirs(); + // check that they were created correctly + if (!parent.exists()) { + throw new IOException("Failed to create directory " + parent.getCanonicalPath()); + } + // mark tmp -rw-r--r-- + tmp.setReadable(true, false); + // write to it + out = new FileOutputStream(tmp); + out.write(content.getBytes()); + // sync to disk + out.getFD().sync(); + // atomic rename + if (!tmp.renameTo(file)) { + throw new IOException("Failed to atomically rename " + file.getCanonicalPath()); + } + } catch (IOException e) { + Slog.e(TAG, "Failed to write update", e); + } finally { + if (tmp != null) { + tmp.delete(); + } + IoUtils.closeQuietly(out); + } + } + + private void install(String content, int version) { + writeUpdate(updateDir, updateContent, content); + writeUpdate(updateDir, updateVersion, Long.toString(version)); + } +} diff --git a/services/tests/servicestests/src/com/android/server/updatable/CertPinInstallReceiverTest.java b/services/tests/servicestests/src/com/android/server/updatable/CertPinInstallReceiverTest.java new file mode 100644 index 000000000000..b6742a104c30 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/updatable/CertPinInstallReceiverTest.java @@ -0,0 +1,243 @@ +/* + * 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 com.android.server.updates; + +import android.content.Context; +import android.content.Intent; +import android.test.AndroidTestCase; +import android.provider.Settings; +import android.util.Base64; +import android.util.Log; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CertificateFactory; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.KeyFactory; +import java.util.HashSet; +import java.io.*; +import libcore.io.IoUtils; + +/** + * Tests for {@link com.android.server.CertPinInstallReceiver} + */ +public class CertPinInstallReceiverTest extends AndroidTestCase { + + private static final String TAG = "CertPinInstallReceiverTest"; + + private static final String PINLIST_ROOT = System.getenv("ANDROID_DATA") + "/misc/keychain/"; + + public static final String PINLIST_CONTENT_PATH = PINLIST_ROOT + "pins"; + public static final String PINLIST_METADATA_PATH = PINLIST_CONTENT_PATH + "metadata"; + + public static final String PINLIST_CONTENT_URL_KEY = "pinlist_content_url"; + public static final String PINLIST_METADATA_URL_KEY = "pinlist_metadata_url"; + public static final String PINLIST_CERTIFICATE_KEY = "config_update_certificate"; + public static final String PINLIST_VERSION_KEY = "pinlist_version"; + + private static final String EXTRA_CONTENT_PATH = "CONTENT_PATH"; + private static final String EXTRA_REQUIRED_HASH = "REQUIRED_HASH"; + private static final String EXTRA_SIGNATURE = "SIGNATURE"; + private static final String EXTRA_VERSION_NUMBER = "VERSION"; + + public static final String TEST_CERT = "" + + "MIIDsjCCAxugAwIBAgIJAPLf2gS0zYGUMA0GCSqGSIb3DQEBBQUAMIGYMQswCQYDVQQGEwJVUzET" + + "MBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEPMA0GA1UEChMGR29v" + + "Z2xlMRAwDgYDVQQLEwd0ZXN0aW5nMRYwFAYDVQQDEw1HZXJlbXkgQ29uZHJhMSEwHwYJKoZIhvcN" + + "AQkBFhJnY29uZHJhQGdvb2dsZS5jb20wHhcNMTIwNzE0MTc1MjIxWhcNMTIwODEzMTc1MjIxWjCB" + + "mDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZp" + + "ZXcxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHdGVzdGluZzEWMBQGA1UEAxMNR2VyZW15IENv" + + "bmRyYTEhMB8GCSqGSIb3DQEJARYSZ2NvbmRyYUBnb29nbGUuY29tMIGfMA0GCSqGSIb3DQEBAQUA" + + "A4GNADCBiQKBgQCjGGHATBYlmas+0sEECkno8LZ1KPglb/mfe6VpCT3GhSr+7br7NG/ZwGZnEhLq" + + "E7YIH4fxltHmQC3Tz+jM1YN+kMaQgRRjo/LBCJdOKaMwUbkVynAH6OYsKevjrOPk8lfM5SFQzJMG" + + "sA9+Tfopr5xg0BwZ1vA/+E3mE7Tr3M2UvwIDAQABo4IBADCB/TAdBgNVHQ4EFgQUhzkS9E6G+x8W" + + "L4EsmRjDxu28tHUwgc0GA1UdIwSBxTCBwoAUhzkS9E6G+x8WL4EsmRjDxu28tHWhgZ6kgZswgZgx" + + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3" + + "MQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB3Rlc3RpbmcxFjAUBgNVBAMTDUdlcmVteSBDb25k" + + "cmExITAfBgkqhkiG9w0BCQEWEmdjb25kcmFAZ29vZ2xlLmNvbYIJAPLf2gS0zYGUMAwGA1UdEwQF" + + "MAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAYiugFDmbDOQ2U/+mqNt7o8ftlEo9SJrns6O8uTtK6AvR" + + "orDrR1AXTXkuxwLSbmVfedMGOZy7Awh7iZa8hw5x9XmUudfNxvmrKVEwGQY2DZ9PXbrnta/dwbhK" + + "mWfoepESVbo7CKIhJp8gRW0h1Z55ETXD57aGJRvQS4pxkP8ANhM="; + + + public static final String TEST_KEY = "" + + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKMYYcBMFiWZqz7SwQQKSejwtnUo" + + "+CVv+Z97pWkJPcaFKv7tuvs0b9nAZmcSEuoTtggfh/GW0eZALdPP6MzVg36QxpCBFGOj8sEIl04p" + + "ozBRuRXKcAfo5iwp6+Os4+TyV8zlIVDMkwawD35N+imvnGDQHBnW8D/4TeYTtOvczZS/AgMBAAEC" + + "gYBxwFalNSwZK3WJipq+g6KLCiBn1JxGGDQlLKrweFaSuFyFky9fd3IvkIabirqQchD612sMb+GT" + + "0t1jptW6z4w2w6++IW0A3apDOCwoD+uvDBXrbFqI0VbyAWUNqHVdaFFIRk2IHGEE6463mGRdmILX" + + "IlCd/85RTHReg4rl/GFqWQJBANgLAIR4pWbl5Gm+DtY18wp6Q3pJAAMkmP/lISCBIidu1zcqYIKt" + + "PoDW4Knq9xnhxPbXrXKv4YzZWHBK8GkKhQ0CQQDBQnXufQcMew+PwiS0oJvS+eQ6YJwynuqG2ejg" + + "WE+T7489jKtscRATpUXpZUYmDLGg9bLt7L62hFvFSj2LO2X7AkBcdrD9AWnBFWlh/G77LVHczSEu" + + "KCoyLiqxcs5vy/TjLaQ8vw1ZQG580/qJnr+tOxyCjSJ18GK3VppsTRaBznfNAkB3nuCKNp9HTWCL" + + "dfrsRsFMrFpk++mSt6SoxXaMbn0LL2u1CD4PCEiQMGt+lK3/3TmRTKNs+23sYS7Ahjxj0udDAkEA" + + "p57Nj65WNaWeYiOfTwKXkLj8l29H5NbaGWxPT0XkWr4PvBOFZVH/wj0/qc3CMVGnv11+DyO+QUCN" + + "SqBB5aRe8g=="; + + private void overrideSettings(String key, String value) throws Exception { + assertTrue(Settings.Secure.putString(mContext.getContentResolver(), key, value)); + Thread.sleep(1000); + } + + private void overrideCert(String value) throws Exception { + overrideSettings(PINLIST_CERTIFICATE_KEY, value); + } + + private String readPins() throws Exception { + return IoUtils.readFileAsString(PINLIST_CONTENT_PATH); + } + + private String readCurrentVersion() throws Exception { + return IoUtils.readFileAsString("/data/misc/keychain/metadata/version"); + } + + private String getNextVersion() throws Exception { + int currentVersion = Integer.parseInt(readCurrentVersion()); + return Integer.toString(currentVersion + 1); + } + + private static String getCurrentHash(String content) throws Exception { + if (content == null) { + return "0"; + } + MessageDigest dgst = MessageDigest.getInstance("SHA512"); + byte[] encoded = content.getBytes(); + byte[] fingerprint = dgst.digest(encoded); + return IntegralToString.bytesToHexString(fingerprint, false); + } + + private static String getHashOfCurrentContent() throws Exception { + String content = IoUtils.readFileAsString("/data/misc/keychain/pins"); + return getCurrentHash(content); + } + + private PrivateKey createKey() throws Exception { + byte[] derKey = Base64.decode(TEST_KEY.getBytes(), Base64.DEFAULT); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(derKey); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + return (PrivateKey) keyFactory.generatePrivate(keySpec); + } + + private X509Certificate createCertificate() throws Exception { + byte[] derCert = Base64.decode(TEST_CERT.getBytes(), Base64.DEFAULT); + InputStream istream = new ByteArrayInputStream(derCert); + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + return (X509Certificate) cf.generateCertificate(istream); + } + + private String makeTemporaryContentFile(String content) throws Exception { + FileOutputStream fw = mContext.openFileOutput("content.txt", mContext.MODE_WORLD_READABLE); + fw.write(content.getBytes(), 0, content.length()); + fw.close(); + return mContext.getFilesDir() + "/content.txt"; + } + + private String createSignature(String content, String version, String requiredHash) + throws Exception { + Signature signer = Signature.getInstance("SHA512withRSA"); + signer.initSign(createKey()); + signer.update(content.trim().getBytes()); + signer.update(version.trim().getBytes()); + signer.update(requiredHash.getBytes()); + String sig = new String(Base64.encode(signer.sign(), Base64.DEFAULT)); + assertEquals(true, + verifySignature(content, version, requiredHash, sig, createCertificate())); + return sig; + } + + public boolean verifySignature(String content, String version, String requiredPrevious, + String signature, X509Certificate cert) throws Exception { + Signature signer = Signature.getInstance("SHA512withRSA"); + signer.initVerify(cert); + signer.update(content.trim().getBytes()); + signer.update(version.trim().getBytes()); + signer.update(requiredPrevious.trim().getBytes()); + return signer.verify(Base64.decode(signature.getBytes(), Base64.DEFAULT)); + } + + private void sendIntent(String contentPath, String version, String required, String sig) { + Intent i = new Intent(); + i.setAction("android.intent.action.UPDATE_PINS"); + i.putExtra(EXTRA_CONTENT_PATH, contentPath); + i.putExtra(EXTRA_VERSION_NUMBER, version); + i.putExtra(EXTRA_REQUIRED_HASH, required); + i.putExtra(EXTRA_SIGNATURE, sig); + mContext.sendBroadcast(i); + } + + private String runTest(String cert, String content, String version, String required, String sig) + throws Exception { + Log.e(TAG, "started test"); + overrideCert(cert); + String contentPath = makeTemporaryContentFile(content); + sendIntent(contentPath, version, required, sig); + Thread.sleep(1000); + return readPins(); + } + + private String runTestWithoutSig(String cert, String content, String version, String required) + throws Exception { + String sig = createSignature(content, version, required); + return runTest(cert, content, version, required, sig); + } + + public void testOverwritePinlist() throws Exception { + Log.e(TAG, "started testOverwritePinList"); + assertEquals("abcde", runTestWithoutSig(TEST_CERT, "abcde", getNextVersion(), getHashOfCurrentContent())); + Log.e(TAG, "started testOverwritePinList"); + } + + public void testBadSignatureFails() throws Exception { + Log.e(TAG, "started testOverwritePinList"); + String text = "blahblah"; + runTestWithoutSig(TEST_CERT, text, getNextVersion(), getHashOfCurrentContent()); + assertEquals(text, runTest(TEST_CERT, "bcdef", getNextVersion(), getCurrentHash(text), "")); + Log.e(TAG, "started testOverwritePinList"); + } + + public void testBadRequiredHashFails() throws Exception { + runTestWithoutSig(TEST_CERT, "blahblahblah", getNextVersion(), getHashOfCurrentContent()); + assertEquals("blahblahblah", runTestWithoutSig(TEST_CERT, "cdefg", getNextVersion(), "0")); + Log.e(TAG, "started testOverwritePinList"); + } + + public void testBadVersionFails() throws Exception { + String text = "blahblahblahblah"; + String version = getNextVersion(); + runTestWithoutSig(TEST_CERT, text, version, getHashOfCurrentContent()); + assertEquals(text, runTestWithoutSig(TEST_CERT, "defgh", version, getCurrentHash(text))); + Log.e(TAG, "started testOverwritePinList"); + } + + public void testOverrideRequiredHash() throws Exception { + runTestWithoutSig(TEST_CERT, "blahblahblah", getNextVersion(), getHashOfCurrentContent()); + assertEquals("blahblahblah", runTestWithoutSig(TEST_CERT, "cdefg", "NONE", "0")); + Log.e(TAG, "started testOverwritePinList"); + } + +} |