summaryrefslogtreecommitdiff
path: root/packages/DynamicSystemInstallationService/src
diff options
context:
space:
mode:
authorTreehugger Robot <treehugger-gerrit@google.com>2020-02-19 11:04:29 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2020-02-19 11:04:29 +0000
commit3bdf29c1f6db23255ca6686d2c4805a11189b705 (patch)
tree9106f9d499c9852c7a96c7baf1f050ea5d4ffc47 /packages/DynamicSystemInstallationService/src
parent195fc891555b9cd5a13e9abf539da258ded92149 (diff)
parenta86e1ab30a174f0003aeafa662450e443be4dc8a (diff)
Merge "Check DSU public key with key revocation list"
Diffstat (limited to 'packages/DynamicSystemInstallationService/src')
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java19
-rw-r--r--packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java87
2 files changed, 87 insertions, 19 deletions
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
index 9bae223a0a3e..7affe8888628 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java
@@ -80,6 +80,7 @@ public class DynamicSystemInstallationService extends Service
static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED";
static final String KEY_DSU_SLOT = "KEY_DSU_SLOT";
static final String DEFAULT_DSU_SLOT = "dsu";
+ static final String KEY_PUBKEY = "KEY_PUBKEY";
/*
* Intent actions
@@ -267,6 +268,7 @@ public class DynamicSystemInstallationService extends Service
long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0);
mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false);
String dsuSlot = intent.getStringExtra(KEY_DSU_SLOT);
+ String publicKey = intent.getStringExtra(KEY_PUBKEY);
if (TextUtils.isEmpty(dsuSlot)) {
dsuSlot = DEFAULT_DSU_SLOT;
@@ -274,7 +276,7 @@ public class DynamicSystemInstallationService extends Service
// TODO: better constructor or builder
mInstallTask =
new InstallationAsyncTask(
- url, dsuSlot, systemSize, userdataSize, this, mDynSystem, this);
+ url, dsuSlot, publicKey, systemSize, userdataSize, this, mDynSystem, this);
mInstallTask.execute();
@@ -408,6 +410,10 @@ public class DynamicSystemInstallationService extends Service
}
private Notification buildNotification(int status, int cause) {
+ return buildNotification(status, cause, null);
+ }
+
+ private Notification buildNotification(int status, int cause, Throwable detail) {
Notification.Builder builder = new Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_system_update_googblue_24dp)
.setProgress(0, 0, false);
@@ -463,7 +469,12 @@ public class DynamicSystemInstallationService extends Service
case STATUS_NOT_STARTED:
if (cause != CAUSE_NOT_SPECIFIED && cause != CAUSE_INSTALL_CANCELLED) {
- builder.setContentText(getString(R.string.notification_install_failed));
+ if (detail instanceof InstallationAsyncTask.ImageValidationException) {
+ builder.setContentText(
+ getString(R.string.notification_image_validation_failed));
+ } else {
+ builder.setContentText(getString(R.string.notification_install_failed));
+ }
} else {
// no need to notify the user if the task is not started, or cancelled.
}
@@ -525,7 +536,7 @@ public class DynamicSystemInstallationService extends Service
break;
}
- Log.d(TAG, "status=" + statusString + ", cause=" + causeString);
+ Log.d(TAG, "status=" + statusString + ", cause=" + causeString + ", detail=" + detail);
boolean notifyOnNotificationBar = true;
@@ -538,7 +549,7 @@ public class DynamicSystemInstallationService extends Service
}
if (notifyOnNotificationBar) {
- mNM.notify(NOTIFICATION_ID, buildNotification(status, cause));
+ mNM.notify(NOTIFICATION_ID, buildNotification(status, cause, detail));
}
for (int i = mClients.size() - 1; i >= 0; i--) {
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
index 438c435ef0e4..7093914aa847 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java
@@ -17,6 +17,7 @@
package com.android.dynsystem;
import android.content.Context;
+import android.gsi.AvbPublicKey;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.MemoryFile;
@@ -51,18 +52,46 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
private static final List<String> UNSUPPORTED_PARTITIONS =
Arrays.asList("vbmeta", "boot", "userdata", "dtbo", "super_empty", "system_other");
- private class UnsupportedUrlException extends RuntimeException {
+ private class UnsupportedUrlException extends Exception {
private UnsupportedUrlException(String message) {
super(message);
}
}
- private class UnsupportedFormatException extends RuntimeException {
+ private class UnsupportedFormatException extends Exception {
private UnsupportedFormatException(String message) {
super(message);
}
}
+ static class ImageValidationException extends Exception {
+ ImageValidationException(String message) {
+ super(message);
+ }
+
+ ImageValidationException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ static class RevocationListFetchException extends ImageValidationException {
+ RevocationListFetchException(Throwable cause) {
+ super(cause);
+ }
+ }
+
+ static class KeyRevokedException extends ImageValidationException {
+ KeyRevokedException(String message) {
+ super(message);
+ }
+ }
+
+ static class PublicKeyException extends ImageValidationException {
+ PublicKeyException(String message) {
+ super(message);
+ }
+ }
+
/** UNSET means the installation is not completed */
static final int RESULT_UNSET = 0;
static final int RESULT_OK = 1;
@@ -97,6 +126,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
private final String mUrl;
private final String mDsuSlot;
+ private final String mPublicKey;
private final long mSystemSize;
private final long mUserdataSize;
private final Context mContext;
@@ -115,6 +145,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
InstallationAsyncTask(
String url,
String dsuSlot,
+ String publicKey,
long systemSize,
long userdataSize,
Context context,
@@ -122,6 +153,7 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
ProgressListener listener) {
mUrl = url;
mDsuSlot = dsuSlot;
+ mPublicKey = publicKey;
mSystemSize = systemSize;
mUserdataSize = userdataSize;
mContext = context;
@@ -157,8 +189,6 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
return null;
}
- // TODO(yochiang): do post-install public key check (revocation list / boot-ramdisk)
-
mDynSystem.finishInstallation();
} catch (Exception e) {
Log.e(TAG, e.toString(), e);
@@ -247,13 +277,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
String listUrl = mContext.getString(R.string.key_revocation_list_url);
mKeyRevocationList = KeyRevocationList.fromUrl(new URL(listUrl));
} catch (IOException | JSONException e) {
- Log.d(TAG, "Failed to fetch Dynamic System Key Revocation List");
mKeyRevocationList = new KeyRevocationList();
- keyRevocationThrowOrWarning(e);
+ imageValidationThrowOrWarning(new RevocationListFetchException(e));
+ }
+ if (mKeyRevocationList.isRevoked(mPublicKey)) {
+ imageValidationThrowOrWarning(new KeyRevokedException(mPublicKey));
}
}
- private void keyRevocationThrowOrWarning(Exception e) throws Exception {
+ private void imageValidationThrowOrWarning(ImageValidationException e)
+ throws ImageValidationException {
if (mIsNetworkUrl) {
throw e;
} else {
@@ -294,7 +327,8 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
}
- private void installImages() throws IOException, InterruptedException {
+ private void installImages()
+ throws IOException, InterruptedException, ImageValidationException {
if (mStream != null) {
if (mIsZip) {
installStreamingZipUpdate();
@@ -306,12 +340,14 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
}
- private void installStreamingGzUpdate() throws IOException, InterruptedException {
+ private void installStreamingGzUpdate()
+ throws IOException, InterruptedException, ImageValidationException {
Log.d(TAG, "To install a streaming GZ update");
installImage("system", mSystemSize, new GZIPInputStream(mStream), 1);
}
- private void installStreamingZipUpdate() throws IOException, InterruptedException {
+ private void installStreamingZipUpdate()
+ throws IOException, InterruptedException, ImageValidationException {
Log.d(TAG, "To install a streaming ZIP update");
ZipInputStream zis = new ZipInputStream(mStream);
@@ -330,7 +366,8 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
}
- private void installLocalZipUpdate() throws IOException, InterruptedException {
+ private void installLocalZipUpdate()
+ throws IOException, InterruptedException, ImageValidationException {
Log.d(TAG, "To install a local ZIP update");
Enumeration<? extends ZipEntry> entries = mZipFile.entries();
@@ -349,8 +386,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
}
}
- private boolean installImageFromAnEntry(ZipEntry entry, InputStream is,
- int numInstalledPartitions) throws IOException, InterruptedException {
+ private boolean installImageFromAnEntry(
+ ZipEntry entry, InputStream is, int numInstalledPartitions)
+ throws IOException, InterruptedException, ImageValidationException {
String name = entry.getName();
Log.d(TAG, "ZipEntry: " + name);
@@ -373,8 +411,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
return true;
}
- private void installImage(String partitionName, long uncompressedSize, InputStream is,
- int numInstalledPartitions) throws IOException, InterruptedException {
+ private void installImage(
+ String partitionName, long uncompressedSize, InputStream is, int numInstalledPartitions)
+ throws IOException, InterruptedException, ImageValidationException {
SparseInputStream sis = new SparseInputStream(new BufferedInputStream(is));
@@ -445,6 +484,24 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog
publishProgress(progress);
}
}
+
+ AvbPublicKey avbPublicKey = new AvbPublicKey();
+ if (!mInstallationSession.getAvbPublicKey(avbPublicKey)) {
+ imageValidationThrowOrWarning(new PublicKeyException("getAvbPublicKey() failed"));
+ } else {
+ String publicKey = toHexString(avbPublicKey.sha1);
+ if (mKeyRevocationList.isRevoked(publicKey)) {
+ imageValidationThrowOrWarning(new KeyRevokedException(publicKey));
+ }
+ }
+ }
+
+ private static String toHexString(byte[] bytes) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02x", b));
+ }
+ return sb.toString();
}
private void close() {