1 /* 2 * Copyright (c) 2022-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #include "inputer_data_impl.h" 17 18 #include <cstddef> 19 #include <regex> 20 #include <vector> 21 22 #include <openssl/sha.h> 23 24 #include "securec.h" 25 26 #include "iam_logger.h" 27 #include "iam_ptr.h" 28 #include "scrypt.h" 29 #include "settings_data_manager.h" 30 #ifdef CUSTOMIZATION_ENTERPRISE_DEVICE_MANAGEMENT_ENABLE 31 #include "security_manager_proxy.h" 32 #endif 33 34 #define LOG_TAG "PIN_AUTH_SDK" 35 36 namespace OHOS { 37 namespace UserIam { 38 namespace PinAuth { 39 namespace { 40 constexpr uint32_t PIN_LEN_FOUR = 4; 41 constexpr uint32_t PIN_LEN_SIX = 6; 42 constexpr uint32_t PIN_LEN_SEVEN = 7; 43 constexpr uint32_t PIN_LEN_NINE = 9; 44 constexpr uint32_t SPECIFY_PIN_COMPLEXITY = 10002; 45 constexpr uint32_t PIN_QUESTION_MIN_LEN = 2; 46 } 47 InputerDataImpl(const InputerGetDataParam & param)48 InputerDataImpl::InputerDataImpl(const InputerGetDataParam ¶m) 49 : mode_(param.mode), algoVersion_(param.algoVersion), algoParameter_(param.algoParameter), 50 inputerSetData_(param.inputerSetData), complexityReg_(param.complexityReg), userId_(param.userId), 51 authIntent_(param.authIntent) 52 { 53 } 54 GetPinData(int32_t authSubType,const std::vector<uint8_t> & dataIn,std::vector<uint8_t> & dataOut,int32_t & errorCode)55 void InputerDataImpl::GetPinData( 56 int32_t authSubType, const std::vector<uint8_t> &dataIn, std::vector<uint8_t> &dataOut, int32_t &errorCode) 57 { 58 IAM_LOGI("start authSubType: %{public}d", authSubType); 59 errorCode = CheckPinComplexity(authSubType, dataIn); 60 if (errorCode != UserAuth::SUCCESS && mode_ == GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL) { 61 IAM_LOGE("CheckPinComplexity enroll failed"); 62 return; 63 } 64 if (mode_ == GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL && authSubType == UserAuth::PIN_PATTERN) { 65 IAM_LOGE("GetPinData Enroll Unsupport Type Pattern"); 66 return; 67 } 68 auto scryptPointer = Common::MakeUnique<Scrypt>(algoParameter_); 69 if (scryptPointer == nullptr) { 70 IAM_LOGE("scryptPointer is nullptr"); 71 return; 72 } 73 if (authSubType == UserAuth::PIN_PATTERN) { 74 std::vector<uint8_t> patternDataIn(dataIn); 75 for (uint8_t &data : patternDataIn) { 76 data += 1; 77 } 78 scryptPointer->GetScrypt(patternDataIn, algoVersion_).swap(dataOut); 79 (void)memset_s(patternDataIn.data(), patternDataIn.size(), 0, patternDataIn.size()); 80 } else { 81 scryptPointer->GetScrypt(dataIn, algoVersion_).swap(dataOut); 82 } 83 if (dataOut.empty()) { 84 IAM_LOGE("get scrypt fail"); 85 return; 86 } 87 if ((algoVersion_ > ALGO_VERSION_V1) && (mode_ == GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL) && 88 (!GetSha256(dataIn, dataOut))) { 89 IAM_LOGE("get sha256 fail"); 90 if (!dataOut.empty()) { 91 (void)memset_s(dataOut.data(), dataOut.size(), 0, dataOut.size()); 92 } 93 dataOut.clear(); 94 } 95 } 96 GetPrivatePinData(int32_t authSubType,const std::vector<uint8_t> & dataIn,std::vector<uint8_t> & dataOut,int32_t & errorCode)97 void InputerDataImpl::GetPrivatePinData( 98 int32_t authSubType, const std::vector<uint8_t> &dataIn, std::vector<uint8_t> &dataOut, int32_t &errorCode) 99 { 100 IAM_LOGI("start authSubType: %{public}d", authSubType); 101 errorCode = UserAuth::SUCCESS; 102 if (mode_ == GET_DATA_MODE_ALL_IN_ONE_PRIVATE_PIN_ENROLL) { 103 if (authSubType == UserAuth::PIN_PATTERN || authSubType == UserAuth::PIN_FOUR) { 104 IAM_LOGE("unsupport type"); 105 return; 106 } 107 if (authSubType == UserAuth::PIN_QUESTION) { 108 if (dataIn.size() < PIN_QUESTION_MIN_LEN) { 109 IAM_LOGE("check question size fail:%{public}zu", dataIn.size()); 110 return; 111 } 112 } else { 113 if (dataIn.size() < PIN_LEN_SIX) { 114 IAM_LOGE("check size fail:%{public}zu", dataIn.size()); 115 return; 116 } 117 } 118 } 119 120 auto scryptPointer = Common::MakeUnique<Scrypt>(algoParameter_); 121 if (scryptPointer == nullptr) { 122 IAM_LOGE("scryptPointer is nullptr"); 123 return; 124 } 125 scryptPointer->GetScrypt(dataIn, algoVersion_).swap(dataOut); 126 if (dataOut.empty()) { 127 IAM_LOGE("get scrypt fail"); 128 return; 129 } 130 } 131 OnSetData(int32_t authSubType,std::vector<uint8_t> data)132 void InputerDataImpl::OnSetData(int32_t authSubType, std::vector<uint8_t> data) 133 { 134 IAM_LOGI("start userId:%{public}d, data size:%{public}zu, algo version:%{public}u, complexityReg size:%{public}zu", 135 userId_, data.size(), algoVersion_, complexityReg_.size()); 136 std::vector<uint8_t> setData; 137 int32_t errorCode = UserAuth::GENERAL_ERROR; 138 switch (mode_) { 139 case GET_DATA_MODE_ALL_IN_ONE_PRIVATE_PIN_ENROLL: 140 case GET_DATA_MODE_ALL_IN_ONE_PRIVATE_PIN_AUTH: 141 GetPrivatePinData(authSubType, data, setData, errorCode); 142 break; 143 default: 144 GetPinData(authSubType, data, setData, errorCode); 145 break; 146 } 147 OnSetDataInner(authSubType, setData, errorCode); 148 if (!data.empty()) { 149 (void)memset_s(data.data(), data.size(), 0, data.size()); 150 } 151 if (!setData.empty()) { 152 (void)memset_s(setData.data(), setData.size(), 0, setData.size()); 153 } 154 } 155 GetSha256(const std::vector<uint8_t> & data,std::vector<uint8_t> & out)156 bool InputerDataImpl::GetSha256(const std::vector<uint8_t> &data, std::vector<uint8_t> &out) 157 { 158 uint8_t sha256Result[SHA256_DIGEST_LENGTH] = {}; 159 if (SHA256(data.data(), data.size(), sha256Result) != sha256Result) { 160 IAM_LOGE("get sha256 fail"); 161 (void)memset_s(sha256Result, SHA256_DIGEST_LENGTH, 0, SHA256_DIGEST_LENGTH); 162 return false; 163 } 164 out.insert(out.end(), sha256Result, sha256Result + SHA256_DIGEST_LENGTH); 165 (void)memset_s(sha256Result, SHA256_DIGEST_LENGTH, 0, SHA256_DIGEST_LENGTH); 166 return true; 167 } 168 OnSetDataInner(int32_t authSubType,std::vector<uint8_t> & setData,int32_t errorCode)169 void InputerDataImpl::OnSetDataInner(int32_t authSubType, std::vector<uint8_t> &setData, int32_t errorCode) 170 { 171 if (inputerSetData_ == nullptr) { 172 IAM_LOGE("inputerSetData is nullptr"); 173 return; 174 } 175 inputerSetData_->OnSetData(authSubType, setData, errorCode); 176 } 177 CheckPinSizeBySubType(int32_t authSubType,size_t size)178 bool InputerDataImpl::CheckPinSizeBySubType(int32_t authSubType, size_t size) 179 { 180 if (mode_ != GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL) { 181 return true; 182 } 183 if (size < PIN_LEN_FOUR) { 184 return false; 185 } 186 switch (authSubType) { 187 case UserAuth::PIN_FOUR: 188 return (size == PIN_LEN_FOUR); 189 case UserAuth::PIN_PATTERN: 190 return (size >= PIN_LEN_FOUR && size <= PIN_LEN_NINE); 191 default: 192 return (size >= PIN_LEN_SIX); 193 } 194 } 195 CheckPinComplexity(int32_t authSubType,const std::vector<uint8_t> & data)196 int32_t InputerDataImpl::CheckPinComplexity(int32_t authSubType, const std::vector<uint8_t> &data) 197 { 198 if (data.empty()) { 199 IAM_LOGE("get empty data"); 200 return UserAuth::COMPLEXITY_CHECK_FAILED; 201 } 202 if (!CheckPinSizeBySubType(authSubType, data.size())) { 203 IAM_LOGE("check data size failed"); 204 return UserAuth::COMPLEXITY_CHECK_FAILED; 205 } 206 std::vector<uint8_t> input = data; 207 input.emplace_back('\0'); 208 if (!CheckEdmPinComplexity(authSubType, input)) { 209 IAM_LOGE("CheckEdmPinComplexity failed"); 210 (void)memset_s(input.data(), input.size(), 0, input.size()); 211 return UserAuth::COMPLEXITY_CHECK_FAILED; 212 } 213 if (!CheckSpecialPinComplexity(input, authSubType)) { 214 IAM_LOGE("CheckSpecialPinComplexity failed"); 215 (void)memset_s(input.data(), input.size(), 0, input.size()); 216 return UserAuth::COMPLEXITY_CHECK_FAILED; 217 } 218 (void)memset_s(input.data(), input.size(), 0, input.size()); 219 return UserAuth::SUCCESS; 220 } 221 CheckSpecialPinComplexity(std::vector<uint8_t> & input,int32_t authSubType)222 bool InputerDataImpl::CheckSpecialPinComplexity(std::vector<uint8_t> &input, int32_t authSubType) 223 { 224 IAM_LOGI("start"); 225 if (mode_ != GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL && 226 !(mode_ == GET_DATA_MODE_ALL_IN_ONE_PIN_AUTH && authIntent_ == SPECIFY_PIN_COMPLEXITY)) { 227 return true; 228 } 229 if (complexityReg_.empty()) { 230 IAM_LOGI("complexityReg is empty"); 231 return true; 232 } 233 const std::string key = "payment_security_level"; 234 int32_t isCheckPinComplexity = 0; 235 if (!SettingsDataManager::GetIntValue(userId_, key, isCheckPinComplexity)) { 236 IAM_LOGI("no exist isCheckPinComplexity"); 237 return true; 238 } 239 if (isCheckPinComplexity == 0) { 240 IAM_LOGI("no need check special pin complexity"); 241 return true; 242 } 243 if (authSubType == UserAuth::PIN_FOUR || authSubType == UserAuth::PIN_PATTERN) { 244 IAM_LOGE("authSubType is PIN_FOUR or PIN_PATTERN"); 245 return false; 246 } 247 if (input.size() < PIN_LEN_SEVEN) { 248 IAM_LOGE("check data size failed"); 249 return false; 250 } 251 return CheckPinComplexityByReg(input, complexityReg_); 252 } 253 CheckEdmPinComplexity(int32_t authSubType,std::vector<uint8_t> & input)254 bool InputerDataImpl::CheckEdmPinComplexity(int32_t authSubType, std::vector<uint8_t> &input) 255 { 256 IAM_LOGI("start"); 257 if (mode_ != GET_DATA_MODE_ALL_IN_ONE_PIN_ENROLL) { 258 return true; 259 } 260 #ifdef CUSTOMIZATION_ENTERPRISE_DEVICE_MANAGEMENT_ENABLE 261 EDM::PasswordPolicy policy; 262 int32_t ret = EDM::SecurityManagerProxy::GetSecurityManagerProxy()->GetPasswordPolicy(policy); 263 if (ret != ERR_OK || policy.complexityReg.empty()) { 264 IAM_LOGE("GetPasswordPolicy failed, check other policy"); 265 return true; 266 } 267 if (authSubType != UserAuth::PIN_MIXED) { 268 IAM_LOGE("GetPasswordPolicy success, authSubType can only be PIN_MIXED"); 269 return false; 270 } 271 return CheckPinComplexityByReg(input, policy.complexityReg); 272 #else 273 IAM_LOGI("This device not support edm"); 274 #endif 275 return true; 276 } 277 CheckPinComplexityByReg(std::vector<uint8_t> & input,const std::string & complexityReg)278 bool InputerDataImpl::CheckPinComplexityByReg(std::vector<uint8_t> &input, const std::string &complexityReg) 279 { 280 try { 281 std::regex regex(complexityReg); 282 bool checkRet = std::regex_match(reinterpret_cast<char*>(input.data()), regex); 283 if (!checkRet) { 284 IAM_LOGE("PIN_MIXED does not pass complexity check"); 285 return false; 286 } 287 } catch (const std::regex_error &e) { 288 IAM_LOGE("create regex failed"); 289 return false; 290 } 291 return true; 292 } 293 } // namespace PinAuth 294 } // namespace UserIam 295 } // namespace OHOS 296