Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(784)

Unified Diff: components/installedapp/android/java/src/org/chromium/device/installedapp/AssociationVerifier.java

Issue 1586563009: IsNativeAppInstalled Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/installedapp/android/java/src/org/chromium/device/installedapp/AssociationVerifier.java
diff --git a/components/installedapp/android/java/src/org/chromium/device/installedapp/AssociationVerifier.java b/components/installedapp/android/java/src/org/chromium/device/installedapp/AssociationVerifier.java
new file mode 100644
index 0000000000000000000000000000000000000000..71c76d6a7ea8aa6f99a7d79b8f89076422bd8daf
--- /dev/null
+++ b/components/installedapp/android/java/src/org/chromium/device/installedapp/AssociationVerifier.java
@@ -0,0 +1,138 @@
+package org.chromium.components.installedapp;
+
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageInfo;
+import android.content.pm.Signature;
+
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+public class AssociationVerifier {
+ private static final String ASSOCIATED_ASSETS_KEY = "associated_assets";
+ private static final String ASSET_DESCRIPTOR_FIELD_TARGET = "target";
+ private static final String ASSET_DESCRIPTOR_WEB = "web";
+ private static final String ASSET_DESCRIPTOR_FIELD_SITE = "site";
+ private static final String ASSET_DESCRIPTOR_FIELD_NAMESPACE = "namespace";
+
+ public static boolean verifyCertFingerprints(
+ String packageName, List<String> sha, PackageManager pm) {
+ Signature[] signatures;
+ try {
+ signatures = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES).signatures;
+ } catch (NameNotFoundException e) {
+ return false;
+ }
+
+ // TODO: Convert this to an array.
+ HashSet<String> signatureStrings = new HashSet<String>(signatures.length);
+ for (Signature sig : signatures) {
+ signatureStrings.add(computeNormalizedSha256Fingerprint(sig.toByteArray()));
+ }
+
+ return signatureStrings.containsAll(sha) && sha.containsAll(signatureStrings);
+ }
+
+ private static List<String> getAssociations(String packageName, PackageManager pm) {
+ Resources resources;
+
+ try {
+ resources = pm.getResourcesForApplication(packageName);
+ } catch (NameNotFoundException e) {
+ return Collections.<String>emptyList();
+ }
+
+ if (resources == null) {
+ return Collections.<String>emptyList();
+ }
+
+ int identifier = resources.getIdentifier(ASSOCIATED_ASSETS_KEY, "array", packageName);
+ System.out.println("Identifier was " + identifier);
+ if (identifier == 0) {
+ return Collections.<String>emptyList();
+ }
+ return Arrays.asList(resources.getStringArray(identifier));
+ }
+
+ public static boolean isOriginAssociatedWithPackage(
+ String packageName, String origin, PackageManager pm) {
+ List<String> associations = getAssociations(packageName, pm);
+ // HashSet<String> associationSet = (new HashSet<>(associations));
+ // System.out.println(associationSet);
+
+ for (String statementString : associations) {
+ try {
+ JSONObject statement = new JSONObject(statementString);
+ String jsonOrigin = statement.getString(ASSET_DESCRIPTOR_FIELD_TARGET);
+ JSONObject webAsset = new JSONObject(jsonOrigin);
+ System.out.println(jsonOrigin);
+
+ // // TODO: Handle this.
+ // JSONArray relations = statement.getJSONArray(ASSET_DESCRIPTOR_FIELD_RELATION);
+ // for (int i = 0; i < relations.length(); i++) {
+ // // statements.add(Statement
+ // // .create(source, target, Relation.create()));
+ // }
+
+ if (!webAsset.getString(ASSET_DESCRIPTOR_FIELD_NAMESPACE)
+ .equals(ASSET_DESCRIPTOR_WEB)) {
+ System.out.println("ASSET WAS NOT WEB");
+ continue;
+ }
+
+ if (webAsset.getString(ASSET_DESCRIPTOR_FIELD_SITE).equals(origin)) {
+ return true;
+ }
+ System.out.println(webAsset.getString(ASSET_DESCRIPTOR_FIELD_SITE)
+ + " failed to match against " + origin);
+ } catch (JSONException e) {
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Computes the hash of the byte array using the specified algorithm, returning a hex string
+ * with a colon between each byte.
+ */
+ public static String computeNormalizedSha256Fingerprint(byte[] cert) {
+ MessageDigest messageDigest;
+ try {
+ messageDigest = MessageDigest.getInstance("SHA-256");
+ } catch (NoSuchAlgorithmException e) {
+ throw new AssertionError("No SHA-256 implementation found.");
+ }
+ messageDigest.update(cert);
+ return byteArrayToHexString(messageDigest.digest());
+ }
+
+ /**
+ * Converts the byte array to an lowercase hexadecimal digits String with a colon character (:)
+ * between each byte.
+ */
+ private static final char[] HEX_DIGITS = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ private static String byteArrayToHexString(byte[] array) {
+ char[] hexString = new char[array.length * 3];
+ int index = 0;
+ for (byte b : array) {
+ hexString[index++] = HEX_DIGITS[(b >>> 4) & 0x0F];
+ hexString[index++] = HEX_DIGITS[b & 0x0F];
+ hexString[index++] = ':';
+ }
+
+ return new String(Arrays.copyOf(hexString, hexString.length - 1));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698