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 &param)
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