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