| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * Copyright (C) 2023 The LineageOS 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.dialer.oem; |
| |
| import android.annotation.SuppressLint; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.content.pm.ProviderInfo; |
| import android.content.pm.Signature; |
| |
| import androidx.annotation.Nullable; |
| |
| import com.android.dialer.common.LogUtil; |
| |
| import java.security.MessageDigest; |
| import java.security.NoSuchAlgorithmException; |
| import java.security.NoSuchProviderException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| /** Utility class to verify Cequint package information. */ |
| final class CequintPackageUtils { |
| |
| private static final int SIGNED_1024 = 0; |
| private static final int SIGNED_2048 = 1; |
| private static final int SIGNED_VZW = 2; |
| private static final int SIGNED_SPRINT = 3; |
| // TODO(a bug): Add test for this signature. |
| private static final int SIGNED_SPRINT_NEW = 4; |
| |
| // Known Caller Name ID fingerprints |
| private static final List<byte[]> callerIdFingerprints = new ArrayList<>(); |
| |
| static { |
| // 1024 signed |
| callerIdFingerprints.add( |
| SIGNED_1024, |
| new byte[] { |
| 0x1A, |
| 0x0C, |
| (byte) 0xF8, |
| (byte) 0x8D, |
| 0x5B, |
| (byte) 0xE2, |
| 0x6A, |
| (byte) 0xED, |
| 0x50, |
| (byte) 0x85, |
| (byte) 0xFE, |
| (byte) 0x88, |
| (byte) 0xA0, |
| (byte) 0x9E, |
| (byte) 0xEC, |
| 0x25, |
| 0x1E, |
| (byte) 0xCA, |
| 0x16, |
| (byte) 0x97, |
| 0x50, |
| (byte) 0xDA, |
| 0x21, |
| (byte) 0xCC, |
| 0x18, |
| (byte) 0xC9, |
| (byte) 0x98, |
| (byte) 0xAF, |
| 0x26, |
| (byte) 0xCD, |
| 0x06, |
| 0x71 |
| }); |
| // 2048 signed |
| callerIdFingerprints.add( |
| SIGNED_2048, |
| new byte[] { |
| (byte) 0xCA, |
| 0x2F, |
| (byte) 0xAE, |
| (byte) 0xF4, |
| 0x09, |
| (byte) 0xEF, |
| 0x4C, |
| 0x79, |
| (byte) 0xF8, |
| 0x4C, |
| (byte) 0xD8, |
| (byte) 0x97, |
| (byte) 0xBF, |
| 0x1A, |
| 0x15, |
| 0x0F, |
| (byte) 0xF0, |
| 0x5E, |
| 0x54, |
| 0x74, |
| (byte) 0xB6, |
| 0x4A, |
| (byte) 0xCA, |
| (byte) 0xCD, |
| 0x05, |
| 0x7E, |
| 0x1E, |
| (byte) 0x98, |
| (byte) 0xC6, |
| 0x1F, |
| 0x5C, |
| 0x45 |
| }); |
| // VZW Package |
| callerIdFingerprints.add( |
| SIGNED_VZW, |
| new byte[] { |
| (byte) 0xE6, |
| 0x7A, |
| 0x0E, |
| (byte) 0xB0, |
| 0x76, |
| 0x4E, |
| (byte) 0xC3, |
| 0x28, |
| (byte) 0xB7, |
| (byte) 0xC1, |
| 0x1B, |
| 0x1B, |
| (byte) 0xD0, |
| (byte) 0x84, |
| 0x28, |
| (byte) 0xA6, |
| 0x16, |
| (byte) 0xD9, |
| (byte) 0xF3, |
| (byte) 0xEB, |
| (byte) 0xB0, |
| 0x20, |
| (byte) 0xA7, |
| (byte) 0xD8, |
| (byte) 0xDF, |
| 0x14, |
| 0x72, |
| (byte) 0x81, |
| 0x4C, |
| 0x13, |
| (byte) 0xF3, |
| (byte) 0xC9 |
| }); |
| |
| // Sprint Package |
| callerIdFingerprints.add( |
| SIGNED_SPRINT, |
| new byte[] { |
| 0x1A, |
| (byte) 0xBA, |
| (byte) 0xA2, |
| (byte) 0x84, |
| 0x0C, |
| 0x61, |
| (byte) 0x96, |
| 0x09, |
| (byte) 0x91, |
| 0x5E, |
| (byte) 0x91, |
| (byte) 0x95, |
| 0x3D, |
| 0x29, |
| 0x3C, |
| (byte) 0x90, |
| (byte) 0xEC, |
| (byte) 0xB4, |
| (byte) 0x89, |
| 0x1D, |
| (byte) 0xC0, |
| (byte) 0xB1, |
| 0x23, |
| 0x58, |
| (byte) 0x98, |
| (byte) 0xEB, |
| (byte) 0xE6, |
| (byte) 0xD4, |
| 0x09, |
| (byte) 0xE5, |
| (byte) 0x8E, |
| (byte) 0x9D |
| }); |
| callerIdFingerprints.add( |
| SIGNED_SPRINT_NEW, |
| new byte[] { |
| 0x27, |
| (byte) 0xF9, |
| 0x6D, |
| (byte) 0xBA, |
| (byte) 0xB7, |
| 0x7B, |
| 0x31, |
| (byte) 0xF6, |
| (byte) 0x95, |
| 0x3E, |
| 0x4C, |
| (byte) 0xD2, |
| (byte) 0xC2, |
| (byte) 0xDE, |
| (byte) 0xFE, |
| 0x15, |
| (byte) 0xF5, |
| (byte) 0xD7, |
| (byte) 0xC7, |
| (byte) 0x8F, |
| 0x07, |
| 0x3D, |
| (byte) 0xD7, |
| 0x16, |
| 0x20, |
| 0x18, |
| (byte) 0xEF, |
| 0x47, |
| 0x6B, |
| 0x09, |
| 0x7C, |
| 0x34 |
| }); |
| } |
| |
| @SuppressLint("PackageManagerGetSignatures") |
| static boolean isCallerIdInstalled( |
| @Nullable PackageManager packageManager, @Nullable String authority) { |
| if (packageManager == null) { |
| LogUtil.i("CequintPackageUtils.isCallerIdInstalled", "failed to get PackageManager!"); |
| return false; |
| } |
| |
| ProviderInfo providerInfo = |
| packageManager.resolveContentProvider(authority, |
| PackageManager.ComponentInfoFlags.of(PackageManager.GET_META_DATA)); |
| if (providerInfo == null) { |
| LogUtil.d( |
| "CequintPackageUtils.isCallerIdInstalled", |
| "no content provider with '%s' authority", |
| authority); |
| return false; |
| } |
| |
| String packageName = providerInfo.packageName; |
| if (packageName == null) { |
| LogUtil.w("CequintPackageUtils.isCallerIdInstalled", "can't get valid package name."); |
| return false; |
| } |
| |
| LogUtil.i( |
| "CequintPackageUtils.isCallerIdInstalled", |
| "content provider package name : " + packageName); |
| |
| try { |
| PackageInfo packageInfo = |
| packageManager.getPackageInfo(packageName, |
| PackageManager.PackageInfoFlags.of(PackageManager.GET_SIGNING_CERTIFICATES)); |
| |
| Signature[] signatures = packageInfo.signingInfo.getSigningCertificateHistory(); |
| if (signatures.length > 1) { |
| LogUtil.w( |
| "CequintPackageUtils.isCallerIdInstalled", "package has more than one signature."); |
| return false; |
| } |
| byte[] sha256Bytes = getSHA256(signatures[0].toByteArray()); |
| |
| for (int i = 0; i < callerIdFingerprints.size(); i++) { |
| if (Arrays.equals(callerIdFingerprints.get(i), sha256Bytes)) { |
| LogUtil.i( |
| "CequintPackageUtils.isCallerIdInstalled", |
| "this is %s Caller Name ID APK.", |
| getApkTypeString(i)); |
| return true; |
| } |
| } |
| } catch (PackageManager.NameNotFoundException e) { |
| LogUtil.e( |
| "CequintPackageUtils.isCallerIdInstalled", |
| "couldn't find package info for the package: %s", |
| packageName, |
| e); |
| } |
| LogUtil.w( |
| "CequintPackageUtils.isCallerIdInstalled", |
| "signature check failed for package: %s", |
| packageName); |
| return false; |
| } |
| |
| // Returns sha256 hash of the signature |
| @Nullable |
| private static byte[] getSHA256(byte[] sig) { |
| MessageDigest digest; |
| try { |
| digest = MessageDigest.getInstance("SHA256", "BC"); |
| } catch (NoSuchAlgorithmException | NoSuchProviderException e) { |
| LogUtil.e("CequintPackageUtils.getSHA256", "", e); |
| return null; |
| } |
| |
| digest.update(sig); |
| return digest.digest(); |
| } |
| |
| private static String getApkTypeString(int index) { |
| switch (index) { |
| case SIGNED_1024: |
| return "1024-signed"; |
| case SIGNED_2048: |
| return "2048-signed"; |
| case SIGNED_VZW: |
| return "VZWPackage"; |
| case SIGNED_SPRINT: |
| default: |
| return "SprintPackage"; |
| } |
| } |
| } |