1 /*
2  * Copyright (C) 2021 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 
17 #include <memory>
18 
19 #include <android-base/file.h>
20 #include <android-base/properties.h>
21 #include <android/api-level.h>
22 #include <androidfw/AssetManager.h>
23 #include <androidfw/ResourceTypes.h>
24 #include <gtest/gtest.h>
25 #include <openssl/sha.h>
26 #include <stdio.h>
27 #include <utils/String8.h>
28 #include <utils/Vector.h>
29 
30 #include "gsi_validation_utils.h"
31 
HexDigitToByte(char c)32 uint8_t HexDigitToByte(char c) {
33   if (c >= '0' && c <= '9') {
34     return c - '0';
35   }
36   if (c >= 'a' && c <= 'f') {
37     return c - 'a' + 10;
38   }
39   if (c >= 'A' && c <= 'Z') {
40     return c - 'A' + 10;
41   }
42   return 0xff;
43 }
44 
HexToBytes(const std::string & hex,std::vector<uint8_t> * bytes)45 bool HexToBytes(const std::string &hex, std::vector<uint8_t> *bytes) {
46   if (hex.size() % 2 != 0) {
47     return false;
48   }
49   bytes->resize(hex.size() / 2);
50   for (unsigned i = 0; i < bytes->size(); i++) {
51     uint8_t hi = HexDigitToByte(hex[i * 2]);
52     uint8_t lo = HexDigitToByte(hex[i * 2 + 1]);
53     if (lo > 0xf || hi > 0xf) {
54       return false;
55     }
56     bytes->at(i) = (hi << 4) | lo;
57   }
58   return true;
59 }
60 
61 const char kNibble2Hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
62                               '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
63 
BytesToHex(const std::vector<uint8_t> & bytes)64 std::string BytesToHex(const std::vector<uint8_t> &bytes) {
65   std::string retval;
66   retval.reserve(bytes.size() * 2 + 1);
67   for (uint8_t byte : bytes) {
68     retval.push_back(kNibble2Hex[0x0F & (byte >> 4)]);
69     retval.push_back(kNibble2Hex[0x0F & byte]);
70   }
71   return retval;
72 }
73 
CreateShaHasher(const std::string & algorithm)74 std::unique_ptr<ShaHasher> CreateShaHasher(const std::string &algorithm) {
75   if (algorithm == "sha1") {
76     return std::make_unique<ShaHasherImpl<SHA_CTX>>(
77         SHA1_Init, SHA1_Update, SHA1_Final, SHA_DIGEST_LENGTH);
78   }
79   if (algorithm == "sha256") {
80     return std::make_unique<ShaHasherImpl<SHA256_CTX>>(
81         SHA256_Init, SHA256_Update, SHA256_Final, SHA256_DIGEST_LENGTH);
82   }
83   if (algorithm == "sha512") {
84     return std::make_unique<ShaHasherImpl<SHA512_CTX>>(
85         SHA512_Init, SHA512_Update, SHA512_Final, SHA512_DIGEST_LENGTH);
86   }
87   return nullptr;
88 }
89 
ReadCommandToString(const std::string & command)90 static std::optional<std::string> ReadCommandToString(const std::string &command) {
91   std::unique_ptr<FILE, decltype(&pclose)> cmd_out_stream(popen(command.c_str(), "re"),
92                                                           pclose);
93 
94   if (!cmd_out_stream) {
95     GTEST_LOG_(ERROR) << "Invocation of cmd: " << command << " failed";
96     return std::nullopt;
97   }
98 
99   int fd = fileno(cmd_out_stream.get());
100   if (fd < 0) {
101     GTEST_LOG_(ERROR) << "Unable to acquire file descriptor for cmd: " << command;
102     return std::nullopt;
103   }
104 
105   std::string output;
106   if (!android::base::ReadFdToString(fd, &output)) {
107     GTEST_LOG_(ERROR) << "Unable to read cmd: " << command << " output to string";
108     return std::nullopt;
109   }
110 
111   return output;
112 }
113 
114 // Returns true iff the device has the specified feature.
DeviceSupportsFeature(const std::string & feature)115 static bool DeviceSupportsFeature(const std::string &feature) {
116   std::optional<std::string> features = ReadCommandToString("pm list features");
117 
118   if (!features.has_value()) {
119     return false;
120   }
121 
122   return features.value().find(feature) != std::string::npos;
123 }
124 
125 // Returns true iff the device has the specified package installed.
DeviceHasPackage(const std::string & package_name)126 static bool DeviceHasPackage(const std::string &package_name) {
127   std::optional<std::string> packages = ReadCommandToString("pm list packages");
128 
129   if (!packages.has_value()) {
130     return false;
131   }
132 
133   return packages.value().find(package_name) != std::string::npos;
134 }
135 
IsWatchDevice()136 static bool IsWatchDevice() {
137   return DeviceSupportsFeature("android.hardware.type.watch");
138 }
139 
IsTvDevice()140 bool IsTvDevice() {
141   return DeviceSupportsFeature("android.hardware.type.television") ||
142          DeviceSupportsFeature("android.software.leanback");
143 }
144 
IsAutomotiveDevice()145 bool IsAutomotiveDevice() {
146   return DeviceSupportsFeature("android.hardware.type.automotive");
147 }
148 
IsVrHeadsetDevice()149 static bool IsVrHeadsetDevice() {
150   android::AssetManager assetManager;
151   // This apk is always available on devices.
152   constexpr const static char *path = "/system/framework/framework-res.apk";
153 
154   if (!assetManager.addAssetPath(android::String8(path), nullptr)) {
155     GTEST_LOG_(ERROR) << "Failed to add asset path";
156     return false;
157   }
158 
159   const android::ResTable& res = assetManager.getResources(false);
160   if (res.getError() != android::NO_ERROR) {
161     GTEST_LOG_(ERROR) << "getResources() invocation failed. Cannot determine device configuration.";
162     return false;
163   }
164 
165   android::Vector<android::ResTable_config> configs;
166   res.getConfigurations(&configs, true);
167   // This loop iterates through various configs of the APK
168   // and searches for the UI mode, which is set to "vrheadset"
169   // for VR headsets.
170   for (const auto &config : configs) {
171     if (config.toString().find("vrheadset") != std::string::npos) {
172       return true;
173     }
174   }
175 
176   return false;
177 }
178 
IsArcDevice()179 static bool IsArcDevice() {
180   return DeviceSupportsFeature("org.chromium.arc") ||
181          DeviceSupportsFeature("org.chromium.arc.device_management");
182 }
183 
IsUserBuild()184 static bool IsUserBuild() {
185   return android::base::GetProperty("ro.build.type", "") == "user";
186 }
187 
188 // Returns whether the Play Store is installed for this build
189 // For User builds, check the Play Store package is user cert signed
190 // For Userdebug just check if the Play Store package exists.
DeviceHasPlayStore()191 static bool DeviceHasPlayStore() {
192   bool has_playstore = DeviceHasPackage("com.android.vending");
193 
194   if (!has_playstore) {
195     return false;
196   }
197 
198   if (IsUserBuild()) {
199     std::optional<std::string> package_dump = ReadCommandToString("pm dump com.android.vending");
200 
201     if (!package_dump.has_value())
202       return false;
203 
204     const std::string playstore_user_cert = "F0:FD:6C:5B:41:0F:25:CB:25:C3:B5:"
205                                             "33:46:C8:97:2F:AE:30:F8:EE:74:11:"
206                                             "DF:91:04:80:AD:6B:2D:60:DB:83";
207 
208     bool certified_playstore = package_dump.value().find(playstore_user_cert) != std::string::npos;
209 
210     if (!certified_playstore) {
211       GTEST_LOG_(INFO) << "Device has a user build but the version of playstore is not certified";
212       return false;
213     }
214 
215     GTEST_LOG_(INFO) << "Device has a user build and a certified version of playstore";
216     return true;
217   }
218 
219   GTEST_LOG_(INFO) << "Device has playstore on a non-user build";
220   return true;
221 }
222 
DeviceHasGmsCore()223 static bool DeviceHasGmsCore() {
224   return DeviceHasPackage("com.google.android.gms");
225 }
226 
IsLowRamDevice()227 static bool IsLowRamDevice() {
228   return (GetSdkLevel() >= __ANDROID_API_O_MR1__) &&
229          DeviceSupportsFeature("android.hardware.ram.low");
230 }
231 
232 // Implementation taken from GmsUtil::isGoDevice()
233 //
234 // Android Go is only for phones and tablets. However, there is
235 // no way to identify if a device is a phone or tablet, so we
236 // must ensure that the device is not any other form factor. New
237 // form factors should be tested against here.
IsGoDevice()238 bool IsGoDevice() {
239   return IsLowRamDevice() && DeviceHasGmsCore() && DeviceHasPlayStore() &&
240          !IsWatchDevice() && !IsTvDevice() && !IsAutomotiveDevice() &&
241          !IsVrHeadsetDevice() && !IsArcDevice();
242 }
243 
ValidatePublicKeyBlob(const std::string & key_blob_to_validate)244 bool ValidatePublicKeyBlob(const std::string &key_blob_to_validate) {
245   if (key_blob_to_validate.empty()) {
246     GTEST_LOG_(ERROR) << "Failed to validate an empty key";
247     return false;
248   }
249 
250   const std::string exec_dir = android::base::GetExecutableDirectory();
251   std::vector<std::string> allowed_key_names = {
252       "q-gsi.avbpubkey", "r-gsi.avbpubkey",    "s-gsi.avbpubkey",
253       "t-gsi.avbpubkey", "qcar-gsi.avbpubkey",
254   };
255   std::vector<std::string> allowed_oem_key_names = {
256       "gki-oem-2024.avbpubkey",
257   };
258   if (!IsGoDevice()) {
259     allowed_key_names.insert(allowed_key_names.end(),
260                              allowed_oem_key_names.begin(),
261                              allowed_oem_key_names.end());
262   }
263   for (const auto &key_name : allowed_key_names) {
264     const auto key_path = exec_dir + "/" + key_name;
265     std::string allowed_key_blob;
266     if (android::base::ReadFileToString(key_path, &allowed_key_blob)) {
267       if (key_blob_to_validate == allowed_key_blob) {
268         GTEST_LOG_(INFO) << "Found matching GSI key: " << key_path;
269         return true;
270       }
271     }
272   }
273   return false;
274 }
275 
276 const uint32_t kCurrentApiLevel = 10000;
277 
ReadApiLevelProps(const std::vector<std::string> & api_level_props)278 static uint32_t ReadApiLevelProps(
279     const std::vector<std::string> &api_level_props) {
280   uint32_t api_level = kCurrentApiLevel;
281   for (const auto &api_level_prop : api_level_props) {
282     api_level = android::base::GetUintProperty<uint32_t>(api_level_prop,
283                                                          kCurrentApiLevel);
284     if (api_level != kCurrentApiLevel) {
285       break;
286     }
287   }
288   return api_level;
289 }
290 
GetSdkLevel()291 uint32_t GetSdkLevel() {
292   uint32_t sdk_level = ReadApiLevelProps({"ro.build.version.sdk"});
293   if (sdk_level == kCurrentApiLevel) {
294     ADD_FAILURE() << "Failed to determine SDK level";
295     return 0;
296   }
297   return sdk_level;
298 }
299 
GetProductFirstApiLevel()300 uint32_t GetProductFirstApiLevel() {
301   uint32_t product_api_level =
302       ReadApiLevelProps({"ro.product.first_api_level", "ro.build.version.sdk"});
303   if (product_api_level == kCurrentApiLevel) {
304     ADD_FAILURE() << "Failed to determine product first API level";
305     return 0;
306   }
307   return product_api_level;
308 }
309 
GetVendorApiLevel()310 uint32_t GetVendorApiLevel() {
311   // "ro.vendor.api_level" is added in Android T.
312   uint32_t vendor_api_level = ReadApiLevelProps({"ro.vendor.api_level"});
313   if (vendor_api_level != kCurrentApiLevel) {
314     return vendor_api_level;
315   }
316   // For pre-T devices, determine the board API level by ourselves.
317   uint32_t product_api_level = GetProductFirstApiLevel();
318   uint32_t board_api_level =
319       ReadApiLevelProps({"ro.board.api_level", "ro.board.first_api_level"});
320   uint32_t api_level = std::min(board_api_level, product_api_level);
321   if (api_level == kCurrentApiLevel) {
322     ADD_FAILURE() << "Failed to determine vendor API level";
323     return 0;
324   }
325   return api_level;
326 }
327 
GetBoardApiLevel()328 std::optional<uint32_t> GetBoardApiLevel() {
329   uint32_t board_api_level =
330       ReadApiLevelProps({"ro.board.api_level", "ro.board.first_api_level"});
331   if (board_api_level == kCurrentApiLevel) {
332     return std::nullopt;
333   }
334   return board_api_level;
335 }
336 
IsReleasedAndroidVersion()337 bool IsReleasedAndroidVersion() {
338   return android::base::GetProperty("ro.build.version.codename", "") == "REL";
339 }
340