blob: 96c562100a7a589ac5c06355bb56bcadc6fc383c [file] [log] [blame]
Makoto Onuki590096a2016-03-25 17:15:30 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.backup;
18
19import android.content.pm.ApplicationInfo;
20import android.content.pm.PackageInfo;
Michal Karpinski528c3e52018-02-07 17:47:10 +000021import android.content.pm.PackageManagerInternal;
Makoto Onuki590096a2016-03-25 17:15:30 -070022import android.content.pm.Signature;
Dan Cashman5c9f527e2018-04-03 16:42:23 -070023import android.content.pm.SigningInfo;
Makoto Onuki590096a2016-03-25 17:15:30 -070024import android.util.Slog;
25
Michal Karpinski528c3e52018-02-07 17:47:10 +000026import com.android.internal.util.ArrayUtils;
27
Makoto Onuki590096a2016-03-25 17:15:30 -070028import java.security.MessageDigest;
29import java.security.NoSuchAlgorithmException;
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.List;
33
34public class BackupUtils {
35 private static final String TAG = "BackupUtils";
36
Michal Karpinski528c3e52018-02-07 17:47:10 +000037 private static final boolean DEBUG = false;
Makoto Onuki590096a2016-03-25 17:15:30 -070038
Michal Karpinski528c3e52018-02-07 17:47:10 +000039 public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target,
40 PackageManagerInternal pmi) {
41 if (target == null || target.packageName == null) {
Makoto Onuki590096a2016-03-25 17:15:30 -070042 return false;
43 }
Makoto Onuki590096a2016-03-25 17:15:30 -070044 // If the target resides on the system partition, we allow it to restore
45 // data from the like-named package in a restore set even if the signatures
46 // do not match. (Unlike general applications, those flashed to the system
47 // partition will be signed with the device's platform certificate, so on
48 // different phones the same system app will have different signatures.)
49 if ((target.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
50 if (DEBUG) Slog.v(TAG, "System app " + target.packageName + " - skipping sig check");
51 return true;
52 }
53
Michal Karpinski528c3e52018-02-07 17:47:10 +000054 // Don't allow unsigned apps on either end
55 if (ArrayUtils.isEmpty(storedSigHashes)) {
Amith Yamasani14c716c2018-03-05 20:39:04 +000056 return false;
57 }
58
Dan Cashman5c9f527e2018-04-03 16:42:23 -070059 SigningInfo signingInfo = target.signingInfo;
60 if (signingInfo == null) {
61 Slog.w(TAG, "signingInfo is empty, app was either unsigned or the flag" +
Michal Karpinski528c3e52018-02-07 17:47:10 +000062 " PackageManager#GET_SIGNING_CERTIFICATES was not specified");
63 return false;
Amith Yamasani14c716c2018-03-05 20:39:04 +000064 }
65
Michal Karpinski528c3e52018-02-07 17:47:10 +000066 if (DEBUG) {
67 Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
Dan Cashman5c9f527e2018-04-03 16:42:23 -070068 + " device=" + signingInfo.getApkContentsSigners());
Michal Karpinski528c3e52018-02-07 17:47:10 +000069 }
70
71 final int nStored = storedSigHashes.size();
72 if (nStored == 1) {
73 // if the app is only signed with one sig, it's possible it has rotated its key
74 // the checks with signing history are delegated to PackageManager
75 // TODO(b/73988180): address the case that app has declared restoreAnyVersion and is
76 // restoring from higher version to lower after having rotated the key (i.e. higher
77 // version has different sig than lower version that we want to restore to)
78 return pmi.isDataRestoreSafe(storedSigHashes.get(0), target.packageName);
79 } else {
80 // the app couldn't have rotated keys, since it was signed with multiple sigs - do
81 // a check to see if we find a match for all stored sigs
Dan Cashman5c9f527e2018-04-03 16:42:23 -070082 // since app hasn't rotated key, we only need to check with current signers
83 ArrayList<byte[]> deviceHashes =
84 hashSignatureArray(signingInfo.getApkContentsSigners());
Michal Karpinski528c3e52018-02-07 17:47:10 +000085 int nDevice = deviceHashes.size();
86 // ensure that each stored sig matches an on-device sig
87 for (int i = 0; i < nStored; i++) {
88 boolean match = false;
89 for (int j = 0; j < nDevice; j++) {
90 if (Arrays.equals(storedSigHashes.get(i), deviceHashes.get(j))) {
91 match = true;
92 break;
93 }
94 }
95 if (!match) {
96 return false;
Amith Yamasani14c716c2018-03-05 20:39:04 +000097 }
98 }
Michal Karpinski528c3e52018-02-07 17:47:10 +000099 // we have found a match for all stored sigs
100 return true;
Amith Yamasani14c716c2018-03-05 20:39:04 +0000101 }
Makoto Onuki590096a2016-03-25 17:15:30 -0700102 }
103
104 public static byte[] hashSignature(byte[] signature) {
105 try {
106 MessageDigest digest = MessageDigest.getInstance("SHA-256");
107 digest.update(signature);
108 return digest.digest();
109 } catch (NoSuchAlgorithmException e) {
110 Slog.w(TAG, "No SHA-256 algorithm found!");
111 }
112 return null;
113 }
114
115 public static byte[] hashSignature(Signature signature) {
116 return hashSignature(signature.toByteArray());
117 }
118
119 public static ArrayList<byte[]> hashSignatureArray(Signature[] sigs) {
120 if (sigs == null) {
121 return null;
122 }
123
124 ArrayList<byte[]> hashes = new ArrayList<>(sigs.length);
125 for (Signature s : sigs) {
126 hashes.add(hashSignature(s));
127 }
128 return hashes;
129 }
130
131 public static ArrayList<byte[]> hashSignatureArray(List<byte[]> sigs) {
132 if (sigs == null) {
133 return null;
134 }
135
136 ArrayList<byte[]> hashes = new ArrayList<>(sigs.size());
137 for (byte[] s : sigs) {
138 hashes.add(hashSignature(s));
139 }
140 return hashes;
141 }
142}