Utils.java revision aef66921e9bf8147cb0f1444ebdb102016d69f3b
16a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen/* 26a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Copyright (C) 2015 The Android Open Source Project 36a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * 46a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Licensed under the Apache License, Version 2.0 (the "License"); 56a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * you may not use this file except in compliance with the License. 66a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * You may obtain a copy of the License at 76a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * 86a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * http://www.apache.org/licenses/LICENSE-2.0 96a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * 106a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Unless required by applicable law or agreed to in writing, software 116a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * distributed under the License is distributed on an "AS IS" BASIS, 126a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * See the License for the specific language governing permissions and 146a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * limitations under the License. 156a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 166a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenpackage com.android.statementservice.retriever; 176a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 186a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport android.content.Context; 196a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport android.content.pm.PackageManager; 206a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport android.content.pm.PackageManager.NameNotFoundException; 216a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport android.content.pm.Signature; 226a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 236a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport java.security.MessageDigest; 246a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport java.security.NoSuchAlgorithmException; 256a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport java.util.ArrayList; 266a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport java.util.HashSet; 276a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenimport java.util.List; 286a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 296a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen/** 306a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Utility library for computing certificate fingerprints. Also includes fields name used by 316a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Statement JSON string. 326a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 336a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wenpublic final class Utils { 346a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 356a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen private Utils() {} 366a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 376a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 386a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Field name for namespace. 396a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 406a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static final String NAMESPACE_FIELD = "namespace"; 416a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 426a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 436a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Supported asset namespaces. 446a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 456a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static final String NAMESPACE_WEB = "web"; 466a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static final String NAMESPACE_ANDROID_APP = "android_app"; 476a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 486a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 496a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Field names in a web asset descriptor. 506a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 516a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static final String WEB_ASSET_FIELD_SITE = "site"; 526a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 536a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 546a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Field names in a Android app asset descriptor. 556a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 566a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static final String ANDROID_APP_ASSET_FIELD_PACKAGE_NAME = "package_name"; 576a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static final String ANDROID_APP_ASSET_FIELD_CERT_FPS = "sha256_cert_fingerprints"; 586a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 596a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 606a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Field names in a statement. 616a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 626a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static final String ASSET_DESCRIPTOR_FIELD_RELATION = "relation"; 636a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static final String ASSET_DESCRIPTOR_FIELD_TARGET = "target"; 64aef66921e9bf8147cb0f1444ebdb102016d69f3bJoseph Wen public static final String DELEGATE_FIELD_DELEGATE = "include"; 656a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 666a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 676a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 'A', 'B', 'C', 'D', 'E', 'F' }; 686a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 696a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 706a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Joins a list of strings, by placing separator between each string. For example, 716a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * {@code joinStrings("; ", Arrays.asList(new String[]{"a", "b", "c"}))} returns 726a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * "{@code a; b; c}". 736a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 746a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static String joinStrings(String separator, List<String> strings) { 756a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen switch(strings.size()) { 766a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen case 0: 776a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return ""; 786a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen case 1: 796a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return strings.get(0); 806a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen default: 816a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen StringBuilder joiner = new StringBuilder(); 826a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen boolean first = true; 836a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen for (String field : strings) { 846a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen if (first) { 856a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen first = false; 866a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } else { 876a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen joiner.append(separator); 886a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 896a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen joiner.append(field); 906a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 916a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return joiner.toString(); 926a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 936a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 946a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 956a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 966a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Returns the normalized sha-256 fingerprints of a given package according to the Android 976a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * package manager. 986a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 996a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static List<String> getCertFingerprintsFromPackageManager(String packageName, 1006a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen Context context) throws NameNotFoundException { 1016a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen Signature[] signatures = context.getPackageManager().getPackageInfo(packageName, 1026a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen PackageManager.GET_SIGNATURES).signatures; 1036a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen ArrayList<String> result = new ArrayList<String>(signatures.length); 1046a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen for (Signature sig : signatures) { 1056a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen result.add(computeNormalizedSha256Fingerprint(sig.toByteArray())); 1066a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1076a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return result; 1086a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1096a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 1106a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 1116a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Computes the hash of the byte array using the specified algorithm, returning a hex string 1126a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * with a colon between each byte. 1136a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 1146a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static String computeNormalizedSha256Fingerprint(byte[] signature) { 1156a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen MessageDigest digester; 1166a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen try { 1176a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen digester = MessageDigest.getInstance("SHA-256"); 1186a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } catch (NoSuchAlgorithmException e) { 1196a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen throw new AssertionError("No SHA-256 implementation found."); 1206a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1216a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen digester.update(signature); 1226a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return byteArrayToHexString(digester.digest()); 1236a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1246a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 1256a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 1266a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Returns true if there is at least one common string between the two lists of string. 1276a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 1286a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen public static boolean hasCommonString(List<String> list1, List<String> list2) { 1296a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen HashSet<String> set2 = new HashSet<>(list2); 1306a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen for (String string : list1) { 1316a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen if (set2.contains(string)) { 1326a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return true; 1336a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1346a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1356a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return false; 1366a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1376a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 1386a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen /** 1396a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * Converts the byte array to an lowercase hexadecimal digits String with a colon character (:) 1406a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen * between each byte. 1416a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen */ 1426a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen private static String byteArrayToHexString(byte[] array) { 1436a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen if (array.length == 0) { 1446a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return ""; 1456a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1466a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen char[] buf = new char[array.length * 3 - 1]; 1476a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen 1486a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen int bufIndex = 0; 1496a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen for (int i = 0; i < array.length; i++) { 1506a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen byte b = array[i]; 1516a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen if (i > 0) { 1526a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen buf[bufIndex++] = ':'; 1536a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1546a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; 1556a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; 1566a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1576a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen return new String(buf); 1586a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen } 1596a34bb2d6a6cbc7a70bdf0c53d238dc28e0b1d58Joseph Wen} 160