1 /*
2 * Copyright (C) 2020 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 <android-base/properties.h>
18 #include <keymint_utils.h>
19 #include <regex.h>
20
21 namespace keymint::javacard {
22
23 namespace {
24
25 constexpr char kPlatformVersionProp[] = "ro.build.version.release";
26 constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?";
27 constexpr size_t kMajorVersionMatch = 1;
28 constexpr size_t kMinorVersionMatch = 3;
29 constexpr size_t kSubminorVersionMatch = 5;
30 constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1;
31
32 constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch";
33 constexpr char kVendorPatchlevelProp[] = "ro.vendor.build.security_patch";
34 constexpr char kPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-([0-9]{2})$";
35 constexpr size_t kYearMatch = 1;
36 constexpr size_t kMonthMatch = 2;
37 constexpr size_t kDayMatch = 3;
38 constexpr size_t kPatchlevelMatchCount = kDayMatch + 1;
39
match_to_uint32(const char * expression,const regmatch_t & match)40 uint32_t match_to_uint32(const char* expression, const regmatch_t& match) {
41 if (match.rm_so == -1) return 0;
42
43 size_t len = match.rm_eo - match.rm_so;
44 std::string s(expression + match.rm_so, len);
45 return std::stoul(s);
46 }
47
wait_and_get_property(const char * prop)48 std::string wait_and_get_property(const char* prop) {
49 std::string prop_value;
50 while (!::android::base::WaitForPropertyCreation(prop))
51 ;
52 prop_value = ::android::base::GetProperty(prop, "" /* default */);
53 return prop_value;
54 }
55
getOsVersion(const char * version_str)56 uint32_t getOsVersion(const char* version_str) {
57 regex_t regex;
58 if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) {
59 return 0;
60 }
61
62 regmatch_t matches[kPlatformVersionMatchCount];
63 int not_match =
64 regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */);
65 regfree(®ex);
66 if (not_match) {
67 return 0;
68 }
69
70 uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]);
71 uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]);
72 uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]);
73
74 return (major * 100 + minor) * 100 + subminor;
75 }
76
77 enum class PatchlevelOutput { kYearMonthDay, kYearMonth };
78
getPatchlevel(const char * patchlevel_str,PatchlevelOutput detail)79 uint32_t getPatchlevel(const char* patchlevel_str, PatchlevelOutput detail) {
80 regex_t regex;
81 if (regcomp(®ex, kPatchlevelRegex, REG_EXTENDED) != 0) {
82 return 0;
83 }
84
85 regmatch_t matches[kPatchlevelMatchCount];
86 int not_match = regexec(®ex, patchlevel_str, kPatchlevelMatchCount, matches, 0 /* flags */);
87 regfree(®ex);
88 if (not_match) {
89 return 0;
90 }
91
92 uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]);
93 uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]);
94
95 if (month < 1 || month > 12) {
96 return 0;
97 }
98
99 switch (detail) {
100 case PatchlevelOutput::kYearMonthDay: {
101 uint32_t day = match_to_uint32(patchlevel_str, matches[kDayMatch]);
102 if (day < 1 || day > 31) {
103 return 0;
104 }
105 return year * 10000 + month * 100 + day;
106 }
107 case PatchlevelOutput::kYearMonth:
108 return year * 100 + month;
109 }
110 }
111
112 } // anonymous namespace
113
getOsVersion()114 uint32_t getOsVersion() {
115 std::string version = wait_and_get_property(kPlatformVersionProp);
116 return getOsVersion(version.c_str());
117 }
118
getOsPatchlevel()119 uint32_t getOsPatchlevel() {
120 std::string patchlevel = wait_and_get_property(kPlatformPatchlevelProp);
121 return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonth);
122 }
123
getVendorPatchlevel()124 uint32_t getVendorPatchlevel() {
125 std::string patchlevel = wait_and_get_property(kVendorPatchlevelProp);
126 return getPatchlevel(patchlevel.c_str(), PatchlevelOutput::kYearMonthDay);
127 }
128
129 } // namespace keymint::javacard
130