1 /* 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 17 #include <keymaster/keymaster_configuration.h> 18 19 #include <regex> 20 #include <string> 21 22 #include <regex.h> 23 24 #define LOG_TAG "keymaster" 25 #include <cutils/log.h> 26 27 #ifndef KEYMASTER_UNIT_TEST_BUILD 28 #include <cutils/properties.h> 29 #else 30 #define PROPERTY_VALUE_MAX 80 /* Value doesn't matter */ 31 void property_get(const char* /* prop_name */, char* /* prop */, const char* /* default */) {} 32 #endif 33 34 #include <keymaster/authorization_set.h> 35 36 namespace keymaster { 37 38 namespace { 39 40 constexpr char kPlatformVersionProp[] = "ro.build.version.release"; 41 constexpr char kPlatformVersionRegex[] = "^([0-9]{1,2})(\\.([0-9]{1,2}))?(\\.([0-9]{1,2}))?"; 42 constexpr size_t kMajorVersionMatch = 1; 43 constexpr size_t kMinorVersionMatch = 3; 44 constexpr size_t kSubminorVersionMatch = 5; 45 constexpr size_t kPlatformVersionMatchCount = kSubminorVersionMatch + 1; 46 47 constexpr char kPlatformPatchlevelProp[] = "ro.build.version.security_patch"; 48 constexpr char kPlatformPatchlevelRegex[] = "^([0-9]{4})-([0-9]{2})-[0-9]{2}$"; 49 constexpr size_t kYearMatch = 1; 50 constexpr size_t kMonthMatch = 2; 51 constexpr size_t kPlatformPatchlevelMatchCount = kMonthMatch + 1; 52 53 uint32_t match_to_uint32(const char* expression, const regmatch_t& match) { 54 if (match.rm_so == -1) 55 return 0; 56 57 size_t len = match.rm_eo - match.rm_so; 58 std::string s(expression + match.rm_so, len); 59 return std::stoul(s); 60 } 61 62 } // anonymous namespace 63 64 keymaster_error_t ConfigureDevice(keymaster2_device_t* dev, uint32_t os_version, 65 uint32_t os_patchlevel) { 66 AuthorizationSet config_params(AuthorizationSetBuilder() 67 .Authorization(keymaster::TAG_OS_VERSION, os_version) 68 .Authorization(keymaster::TAG_OS_PATCHLEVEL, os_patchlevel)); 69 return dev->configure(dev, &config_params); 70 } 71 72 keymaster_error_t ConfigureDevice(keymaster2_device_t* dev) { 73 char version_str[PROPERTY_VALUE_MAX]; 74 property_get(kPlatformVersionProp, version_str, "" /* default */); 75 uint32_t version = GetOsVersion(version_str); 76 77 char patchlevel_str[PROPERTY_VALUE_MAX]; 78 property_get(kPlatformPatchlevelProp, patchlevel_str, "" /* default */); 79 uint32_t patchlevel = GetOsPatchlevel(patchlevel_str); 80 81 return ConfigureDevice(dev, version, patchlevel); 82 } 83 84 uint32_t GetOsVersion(const char* version_str) { 85 regex_t regex; 86 if (regcomp(®ex, kPlatformVersionRegex, REG_EXTENDED)) { 87 ALOGE("Failed to compile version regex! (%s)", kPlatformVersionRegex); 88 return 0; 89 } 90 91 regmatch_t matches[kPlatformVersionMatchCount]; 92 if (regexec(®ex, version_str, kPlatformVersionMatchCount, matches, 0 /* flags */)) { 93 ALOGI("Platform version string does not match expected format. Using version 0."); 94 return 0; 95 } 96 97 uint32_t major = match_to_uint32(version_str, matches[kMajorVersionMatch]); 98 uint32_t minor = match_to_uint32(version_str, matches[kMinorVersionMatch]); 99 uint32_t subminor = match_to_uint32(version_str, matches[kSubminorVersionMatch]); 100 101 return (major * 100 + minor) * 100 + subminor; 102 } 103 104 uint32_t GetOsPatchlevel(const char* patchlevel_str) { 105 regex_t regex; 106 if (regcomp(®ex, kPlatformPatchlevelRegex, REG_EXTENDED) != 0) { 107 ALOGE("Failed to compile platform patchlevel regex! (%s)", kPlatformPatchlevelRegex); 108 return 0; 109 } 110 111 regmatch_t matches[kPlatformPatchlevelMatchCount]; 112 if (regexec(®ex, patchlevel_str, kPlatformPatchlevelMatchCount, matches, 0 /* flags */)) { 113 ALOGI("Platform patchlevel string does not match expected format. Using patchlevel 0"); 114 return 0; 115 } 116 117 uint32_t year = match_to_uint32(patchlevel_str, matches[kYearMatch]); 118 uint32_t month = match_to_uint32(patchlevel_str, matches[kMonthMatch]); 119 120 if (month < 1 || month > 12) { 121 ALOGE("Invalid patch month %d", month); 122 return 0; 123 } 124 return year * 100 + month; 125 } 126 127 } // namespace keymaster 128