• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# PIN Authentication
2
3## Overview
4
5### Function
6
7Personal Identification Number (PIN) authentication provides user authentication capabilities in identity authentication scenarios, such as device unlocking, payment, and app logins. After a user registers a PIN, the PIN authentication (Pin_auth) module unlocks the device only when the correct PIN is entered. The figure below shows the architecture of PIN authentication.
8
9The Pin_auth driver is developed based on the Hardware Driver Foundation (HDF). The Pin_auth driver model shields hardware differences and provides stable PIN authentication capabilities for the user User_auth framework (User_auth) and PIN authentication system ability (SA). The PIN authentication capabilities include obtaining the PIN authentication executor list, executor information, and anti-brute force information of the specified template, comparing the template ID list of the executor and that of User_auth, enrolling or deleting PINs, and performing PIN authentication.
10
11**Figure 1** PIN authentication architecture
12
13![image](figures/pin_auth_architecture.png "PIN authentication architecture")
14
15### Basic Concepts
16The identity authentication consists of User_auth and basic authentication services (including PIN authentication and facial recognition). It supports basic functions such as setting and deleting user credentials and performing authentication.
17
18- Executor
19
20  The executor collects, processes, stores, and compares data for authentication. Each authentication service provides the executor capabilities, which are scheduled by User_auth to implement basic capabilities.
21
22- Executor security level
23
24  Security level required for the execution environment of an executor.
25
26- Executor role
27
28  - Executor: independently completes the entire process of credential registration and identity authentication. The executor can collect, process, store, and compare data to complete the authentication.
29
30  - Collector: only collects data during user authentication. It needs to work with the authenticator to complete user authentication.
31
32  - Authenticator: only processes data, obtains the stored credential template, and compares it with the authentication information generated.
33
34- Executor type
35
36  The authentication algorithm varies depending on the authentication mode and device used. Different executor types are defined based on the supported algorithm type or the device in use.
37
38- User_auth public key & executor public key
39
40  To ensure user data security and authentication result accuracy, measures must be taken to protect the integrity of the key information exchanged between User_auth and basic authentication services. Public keys must be exchanged when the executor provided by a basic authentication service interworks with User_auth.
41
42    - The executor uses the User_auth public key to verify scheduling instructions.
43
44    - User_auth uses the executor public key to verify the authentication result accuracy and the integrity of the information exchanged with the executor.
45
46
47- PIN authentication credential template
48
49  Authentication credentials are generated and stored by the authentication service when users set authentication credentials. Each template has an ID to index a set of template information files. The template information needs to be compared with the authentication data generated during authentication to complete identity authentication.
50
51- Data verification by the executor
52
53  User_auth manages the mappings between user identities and credential IDs in a unified manner. When connecting to User_auth, the executor obtains the template ID list from User_auth and updates its template ID list based on the template ID list obtained.
54
55### Working Principles
56
57The Pin_auth driver provides basic PIN authentication capabilities for the upper-layer User_auth and Pin_auth service to ensure successful PIN authentication. You can develop drivers to call Hardware Device Interface (HDI) APIs based on the HDF and the chip you use.
58
59**Figure 2** Pin_auth service and Pin_auth driver APIs
60
61![image](figures/pin_auth_service_and_driver_interaction.png "interaction between the pin_auth service and driver")
62
63### Constraints
64PIN authentication must be implemented in a Trusted Execution Environment (TEE), and the confidential information, such as PINs and credentials, must be stored in a TEE.
65## Development Guidelines
66
67### When to Use
68The Pin_auth driver provides basic PIN authentication capabilities for the User_auth and Pin_auth service to ensure successful PIN authentication.
69
70### Available APIs
71
72**Table 1** Available APIs
73
74| API                                                      | Description                                                    |
75| ------------------------------------------------------------ | ------------------------------------------------------------ |
76| GetExecutorList(std::vector<sptr<IExecutor>>& executorList)  | Obtains the executor list.                                            |
77| GetExecutorInfo(ExecutorInfo& info)                          | Obtains information about an executor.                                            |
78| GetTemplateInfo(uint64_t templateId, TemplateInfo& info)     | Obtains information about a template.                              |
79| OnRegisterFinish(const std::vector<uint64_t>& templateIdList,<br>const std::vector<uint8_t>& frameworkPublicKey,<br>const std::vector<uint8_t>&  extraInfo) | Obtains the public key and template ID list from User_auth after the executor is registered successfully.|
80| OnSetData(uint64_t scheduleId, uint64_t authSubType, <br>const std::vector<uint8_t> &data) | Called to return the subtype and anonymized data of PIN authentication.                     |
81| Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,<br>const sptr<IExecutorCallback>& callbackObj) | Enrolls a PIN.                                             |
82| Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj) | Starts PIN authentication.                                             |
83| Delete(uint64_t templateId)                                  | Deletes a PIN template.                                             |
84| Cancel(uint64_t scheduleId)                                  | Cancels an operation.                                |
85| SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,<br>const sptr<IExecutorCallback>& callbackObj) | Reserved.                                             |
86
87**Table 2** Callbacks
88
89| API                                                      | Description            |
90| ------------------------------------------------------------ | -------------------- |
91| IExecutorCallback::OnResult(int32_t code, const std::vector<uint8_t>& extraInfo) | Called to return the operation result.|
92| IExecutorCallback::OnGetData(uint64_t scheduleId, const std::vector<uint8_t>& salt,<br> uint64_t authSubType)| Called to return the PIN information obtained. |
93
94### How to Develop
95
96The following uses the RK3568 platform as an example to demonstrate how to develop the Pin_auth driver.
97
98The directory structure is as follows:
99
100```text
101// drivers/peripheral/pin_auth
102├── BUILD.gn # Build script
103├── bundle.json # Module description file
104├── test # Test cases
105└── hdi_service # Pin_auth driver implementation
106    ├── BUILD.gn # Build script
107    ├── adaptor # Implementation of related algorithms
108    ├── common # Implementation of common interfaces
109    ├── database # Database implementation
110    ├── main # Entry for implementing PIN-related functions
111    └── service # Entry for implementing the Pin_auth driver
112        ├── inc # Header files
113        └── src
114            ├── executor_impl.cpp # Implementation of authentication and enrollment APIs
115            ├── pin_auth_interface_driver.cpp # Pin_auth driver entry
116            └── pin_auth_interface_service.cpp # Implementation of the APIs for obtaining the executor list
117```
118
119The development procedure is as follows:
120
1211. Develop the Pin_auth driver based on the HDF. The **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions are used. For details about the code, see [pin_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/pin_auth/hdi_service/service/src/pin_auth_interface_driver.cpp).
122
123   ```c++
124   // Create the PinAuthInterfaceService object by using the custom HdfPinAuthInterfaceHost object, which consists of the IoService object and HDI service.
125   struct HdfPinAuthInterfaceHost {
126       struct IDeviceIoService ioService;
127       OHOS::sptr<OHOS::IRemoteObject> stub;
128   };
129
130   // Enable the IPC service to call the response API.
131   static int32_t PinAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,  struct HdfSBuf *reply)
132   {
133       IAM_LOGI("start");
134       auto *hdfPinAuthInterfaceHost = CONTAINER_OF(client->device->service,
135           struct HdfPinAuthInterfaceHost, ioService);
136
137       OHOS::MessageParcel *dataParcel = nullptr;
138       OHOS::MessageParcel *replyParcel = nullptr;
139       OHOS::MessageOption option;
140
141       if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
142           IAM_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__);
143           return HDF_ERR_INVALID_PARAM;
144       }
145       if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
146           IAM_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__);
147           return HDF_ERR_INVALID_PARAM;
148       }
149
150       return hdfPinAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
151   }
152
153   // Initialize the HdfPinAuthInterfaceDriver object.
154   static int HdfPinAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
155   {
156       IAM_LOGI("start");
157       std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi =
158           OHOS::UserIAM::Common::MakeShared<OHOS::UserIAM::PinAuth::PinAuth>();
159       constexpr uint32_t SUCCESS = 0;
160       if (pinHdi == nullptr || pinHdi->Init() != SUCCESS) {
161           IAM_LOGE("PIN HAL initialization failed");
162           return HDF_FAILURE;
163       }
164       return HDF_SUCCESS;
165   }
166
167   // Bind the service provided by the Pin_auth driver to the HDF.
168   static int HdfPinAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
169   {
170       IAM_LOGI("start");
171       auto *hdfPinAuthInterfaceHost = new (std::nothrow) HdfPinAuthInterfaceHost;
172       if (hdfPinAuthInterfaceHost == nullptr) {
173           IAM_LOGE("%{public}s: Failed to create HdfPinAuthInterfaceHost object", __func__);
174           return HDF_FAILURE;
175       }
176
177       hdfPinAuthInterfaceHost->ioService.Dispatch = PinAuthInterfaceDriverDispatch;
178       hdfPinAuthInterfaceHost->ioService.Open = NULL;
179       hdfPinAuthInterfaceHost->ioService.Release = NULL;
180
181       auto serviceImpl = IPinAuthInterface::Get(true);
182       if (serviceImpl == nullptr) {
183           IAM_LOGE("%{public}s: Failed to implement the service", __func__);
184           return HDF_FAILURE;
185       }
186
187       hdfPinAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
188           IPinAuthInterface::GetDescriptor());
189       if (hdfPinAuthInterfaceHost->stub == nullptr) {
190           IAM_LOGE("%{public}s: Failed to get stub object", __func__);
191           return HDF_FAILURE;
192       }
193
194       deviceObject->service = &hdfPinAuthInterfaceHost->ioService;
195       IAM_LOGI("success");
196       return HDF_SUCCESS;
197   }
198
199   // Release resources of the Pin_auth driver.
200   static void HdfPinAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
201   {
202       IAM_LOGI("start");
203       auto *hdfPinAuthInterfaceHost = CONTAINER_OF(deviceObject->service,
204           struct HdfPinAuthInterfaceHost, ioService);
205       delete hdfPinAuthInterfaceHost;
206       IAM_LOGI("success");
207   }
208
209   static struct HdfDriverEntry g_pinAuthInterfaceDriverEntry = {
210       .moduleVersion = 1,
211       .moduleName = "pinauth_interface_service",
212       .Bind = HdfPinAuthInterfaceDriverBind,
213       .Init = HdfPinAuthInterfaceDriverInit,
214       .Release = HdfPinAuthInterfaceDriverRelease,
215   };
216
217   // Call HDF_INIT to register the driver entry with the HDF. When loading the driver, the HDF calls the Bind() function and then the Init() function. If the Init() function fails to be called, the HDF will call Release() to release driver resources and exit the driver model.
218   HDF_INIT(g_pinauthinterfaceDriverEntry);
219   ```
220
221
222
2231. Obtain the executor list. For details about the code, see [pin_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/pin_auth/hdi_service/service/src/pin_auth_interface_service.cpp).
224
225   ```c++
226   // Executor implementation class
227   class ExecutorImpl : public IExecutor, public NoCopyable {
228   public:
229       explicit ExecutorImpl(std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi);
230       virtual ~ExecutorImpl() {}
231       int32_t GetExecutorInfo(ExecutorInfo &info) override;
232       int32_t GetTemplateInfo(uint64_t templateId, TemplateInfo &info) override;
233       int32_t OnRegisterFinish(const std::vector<uint64_t> &templateIdList,
234           const std::vector<uint8_t> &frameworkPublicKey, const std::vector<uint8_t> &extraInfo) override;
235       int32_t OnSetData(uint64_t scheduleId, uint64_t authSubType, const std::vector<uint8_t> &data) override;
236       int32_t Enroll(uint64_t scheduleId, const std::vector<uint8_t> &extraInfo,
237           const sptr<IExecutorCallback> &callbackObj) override;
238       int32_t Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t> &extraInfo,
239           const sptr<IExecutorCallback> &callbackObj) override;
240       int32_t Delete(uint64_t templateId) override;
241       int32_t Cancel(uint64_t scheduleId) override;
242       int32_t SendCommand(int32_t commandId, const std::vector<uint8_t> &extraInfo,
243           const sptr<IExecutorCallback> &callbackObj) override;
244
245   private:
246       class ScheduleMap {
247       public:
248           uint32_t AddScheduleInfo(const uint64_t scheduleId, const uint32_t commandId,
249               const sptr<IExecutorCallback> callback, const uint64_t templateId, const std::vector<uint8_t> salt);
250           uint32_t GetScheduleInfo(const uint64_t scheduleId, uint32_t &commandId, sptr<IExecutorCallback> &callback,
251               uint64_t &templateId, std::vector<uint8_t> &salt);
252           uint32_t DeleteScheduleId(const uint64_t scheduleId);
253
254       private:
255           struct ScheduleInfo {
256               uint32_t commandId;
257               sptr<IExecutorCallback> callback;
258               uint64_t templateId;
259               std::vector<uint8_t> salt;
260           };
261
262           std::mutex mutex_;
263           std::map<uint64_t, struct ScheduleInfo> scheduleInfo_;
264       };
265
266   private:
267       uint32_t NewSalt(std::vector<uint8_t> &salt);
268       void CallError(const sptr<IExecutorCallback> &callbackObj, const uint32_t errorCode);
269       std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi_;
270       ScheduleMap scheduleMap_;
271   };
272
273   // Obtain the executor list and create an executor (example only).
274   int32_t PinAuthInterfaceService::GetExecutorList(std::vector<sptr<IExecutor>> &executorList)
275   {
276       IAM_LOGI("start");
277       std::shared_ptr<OHOS::UserIAM::PinAuth::PinAuth> pinHdi =
278           OHOS::UserIAM::Common::MakeShared<OHOS::UserIAM::PinAuth::PinAuth>();
279       if (pinHdi == nullptr) {
280           IAM_LOGE("Failed to generate pinHdi");
281           return HDF_FAILURE;
282       }
283       sptr<IExecutor> executor = new (std::nothrow) ExecutorImpl(pinHdi);
284       if (executor == nullptr) {
285           IAM_LOGE("Failed to generate executor");
286           return HDF_FAILURE;
287       }
288       executorList.push_back(executor);
289       IAM_LOGI("end");
290       return HDF_SUCCESS;
291   }
292   ```
293
294
295
2961. Implement each function of the executor. For details about the code, see [executor_impl.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/pin_auth/hdi_service/service/src/executor_impl.cpp).
297
298   ```c++
299   // Obtain executor information (example only).
300   int32_t ExecutorImpl::GetExecutorInfo(ExecutorInfo &info)
301   {
302       IAM_LOGI("start");
303       constexpr unsigned short SENSOR_ID = 1;
304       info.sensorId = SENSOR_ID;
305       info.executorType = EXECUTOR_TYPE;
306       info.executorRole = ExecutorRole::ALL_IN_ONE;
307       info.authType = AuthType::PIN;
308       if (pinHdi_ == nullptr) {
309           IAM_LOGE("pinHdi_ is nullptr");
310           return HDF_FAILURE;
311       }
312       uint32_t eslRet = 0;
313       int32_t result = pinHdi_->GetExecutorInfo(info.publicKey, eslRet);
314       if (result != SUCCESS) {
315           IAM_LOGE("Failed to get ExecutorInfo, error code : %{public}d", result);
316           return result;
317       }
318       info.esl = static_cast<ExecutorSecureLevel>(eslRet);
319
320       return HDF_SUCCESS;
321   }
322
323   // Obtain template information based on templateId.
324   int32_t ExecutorImpl::GetTemplateInfo(uint64_t templateId, TemplateInfo &info)
325   {
326       IAM_LOGI("start");
327       if (pinHdi_ == nullptr) {
328           IAM_LOGE("pinHdi_ is nullptr");
329           return HDF_FAILURE;
330       }
331       OHOS::UserIAM::PinAuth::PinCredentialInfo infoRet = {};
332       int32_t result = pinHdi_->QueryPinInfo(templateId, infoRet);
333       if (result != SUCCESS) {
334           IAM_LOGE("Failed to get TemplateInfo, error code : %{public}d", result);
335           return result;
336       }
337       /* subType is stored in extraInfo. */
338       info.extraInfo.resize(infoRet.subType);
339       if (memcpy_s(&(info.extraInfo[0]), sizeof(infoRet.subType), &(infoRet.subType), sizeof(infoRet.subType)) != EOK) {
340           IAM_LOGE("Failed to copy subType to extraInfo.");
341           return HDF_FAILURE;
342       }
343
344       info.executorType = EXECUTOR_TYPE;
345       info.remainAttempts = infoRet.remainTimes;
346       info.lockoutDuration = infoRet.freezingTime;
347
348       return HDF_SUCCESS;
349   }
350
351   // After the executor is successfully registered, obtain the public key and template ID list from User_auth and save the public key obtained. The executor compares its template ID list with the template ID list obtained and updates its template ID list.
352   int32_t ExecutorImpl::OnRegisterFinish(const std::vector<uint64_t> &templateIdList,
353       const std::vector<uint8_t> &frameworkPublicKey, const std::vector<uint8_t> &extraInfo)
354   {
355       IAM_LOGI("start");
356       static_cast<void>(frameworkPublicKey);
357       static_cast<void>(extraInfo);
358       if (pinHdi_ == nullptr) {
359           IAM_LOGE("pinHdi_ is nullptr");
360           return HDF_FAILURE;
361       }
362       int32_t result = pinHdi_->VerifyTemplateData(templateIdList);
363       if (result != SUCCESS) {
364           IAM_LOGE("Failed to verify templateData");
365           return result;
366       }
367
368       return HDF_SUCCESS;
369   }
370
371   // Enroll the PIN.
372   int32_t ExecutorImpl::Enroll(uint64_t scheduleId, const std::vector<uint8_t> &extraInfo,
373       const sptr<IExecutorCallback> &callbackObj)
374   {
375       IAM_LOGI("start");
376       if (callbackObj == nullptr) {
377           IAM_LOGE("callbackObj is nullptr");
378           return HDF_FAILURE;
379       }
380       static_cast<void>(extraInfo);
381       std::vector<uint8_t> salt;
382       if (NewSalt(salt) != HDF_SUCCESS) {
383           IAM_LOGE("new salt failed");
384           CallError(callbackObj, HDF_FAILURE);
385           return HDF_FAILURE;
386       }
387       int32_t result = scheduleMap_.AddScheduleInfo(scheduleId, ENROLL_PIN, callbackObj, 0, salt);
388       if (result != HDF_SUCCESS) {
389           IAM_LOGE("Failed to add scheduleInfo, error code : %{public}d", result);
390           CallError(callbackObj, HDF_FAILURE);
391           return result;
392       }
393       result = callbackObj->OnGetData(scheduleId, salt, 0);
394       if (result != SUCCESS) {
395           IAM_LOGE("Failed to enroll PIN , error code : %{public}d", result);
396           // If the enrollment fails, delete scheduleId of scheduleMap.
397           if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) {
398               IAM_LOGI("Failed to delete scheduleId");
399           }
400           return result;
401       }
402
403       return HDF_SUCCESS;
404   }
405
406   // Implement the callback for returning data.
407   int32_t ExecutorImpl::OnSetData(uint64_t scheduleId, uint64_t authSubType, const std::vector<uint8_t> &data)
408   {
409       IAM_LOGI("start");
410       if (pinHdi_ == nullptr) {
411           IAM_LOGE("pinHdi_ is nullptr");
412           return HDF_FAILURE;
413       }
414       std::vector<uint8_t> resultTlv;
415       int32_t result = SUCCESS;
416       constexpr uint32_t INVALID_ID = 2;
417       uint32_t commandId = INVALID_ID;
418       sptr<IExecutorCallback> callback = nullptr;
419       uint64_t templateId = 0;
420       std::vector<uint8_t> salt(0, 0);
421       if (scheduleMap_.GetScheduleInfo(scheduleId, commandId, callback, templateId, salt) != HDF_SUCCESS) {
422           IAM_LOGE("Failed to get ScheduleInfo, error code : %{public}d", result);
423           return HDF_FAILURE;
424       }
425       switch (commandId) {
426           case ENROLL_PIN:
427               result = pinHdi_->EnrollPin(scheduleId, authSubType, salt, data, resultTlv);
428               if (result != SUCCESS) {
429                   IAM_LOGE("Failed to enroll PIN, error code : %{public}d", result);
430               }
431               break;
432           case AUTH_PIN:
433               result = pinHdi_->AuthPin(scheduleId, templateId, data, resultTlv);
434               if (result != SUCCESS) {
435                   IAM_LOGE("Failed to authenticate PIN, error code : %{public}d", result);
436               }
437               break;
438           default:
439               IAM_LOGE("Error commandId");
440       }
441
442       if (callback->OnResult(result, resultTlv) != SUCCESS) {
443           IAM_LOGE("callbackObj Pin failed");
444       }
445       // Delete scheduleId from scheduleMap when the enrollment and authentication are successful.
446       if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) {
447           IAM_LOGI("Failed to delete scheduleId");
448       }
449
450       return HDF_SUCCESS;
451   }
452   // Perform PIN authentication.
453   int32_t ExecutorImpl::Authenticate(uint64_t scheduleId, uint64_t templateId, const std::vector<uint8_t> &extraInfo,
454       const sptr<IExecutorCallback> &callbackObj)
455   {
456       IAM_LOGI("start");
457       if (callbackObj == nullptr) {
458           IAM_LOGE("callbackObj is nullptr");
459           return HDF_FAILURE;
460       }
461       if (pinHdi_ == nullptr) {
462           IAM_LOGE("pinHdi_ is nullptr");
463           CallError(callbackObj, HDF_FAILURE);
464           return HDF_FAILURE;
465       }
466       static_cast<void>(extraInfo);
467       std::vector<uint8_t> salt;
468       int32_t result = pinHdi_->GetSalt(templateId, salt);
469       if (result  != SUCCESS) {
470           IAM_LOGE("Failed to get salt, error code : %{public}d", result);
471           CallError(callbackObj, HDF_FAILURE);
472           return result;
473       }
474       result = scheduleMap_.AddScheduleInfo(scheduleId, AUTH_PIN, callbackObj, templateId, salt);
475       if (result != HDF_SUCCESS) {
476           IAM_LOGE("Failed to add scheduleInfo, error code : %{public}d", result);
477           CallError(callbackObj, HDF_FAILURE);
478           return result;
479       }
480       result = callbackObj->OnGetData(scheduleId, salt, 0);
481       if (result != SUCCESS) {
482           IAM_LOGE("Failed to authenticate PIN, error code : %{public}d", result);
483           // If the authentication fails, delete scheduleId of scheduleMap.
484           if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) {
485               IAM_LOGI("Failed to delete scheduleId");
486           }
487           return result;
488       }
489
490       return HDF_SUCCESS;
491   }
492
493   // Delete the PIN template.
494   int32_t ExecutorImpl::Delete(uint64_t templateId)
495   {
496       IAM_LOGI("start");
497       if (pinHdi_ == nullptr) {
498           IAM_LOGE("pinHdi_ is nullptr");
499           return HDF_FAILURE;
500       }
501       int32_t result = pinHdi_->DeleteTemplate(templateId);
502       if (result != SUCCESS) {
503           IAM_LOGE("Failed to verify templateData, error code : %{public}d", result);
504           return result;
505       }
506
507       return HDF_SUCCESS;
508   }
509
510   // Cancel the operation based on the specified scheduleId.
511   int32_t ExecutorImpl::Cancel(uint64_t scheduleId)
512   {
513       IAM_LOGI("start");
514       if (scheduleMap_.DeleteScheduleId(scheduleId) != HDF_SUCCESS) {
515           IAM_LOGE("scheduleId is not found");
516           return HDF_FAILURE;
517       }
518       return HDF_SUCCESS;
519   }
520
521   // API reserved.
522   int32_t ExecutorImpl::SendCommand(int32_t commandId, const std::vector<uint8_t> &extraInfo,
523       const sptr<IExecutorCallback> &callbackObj)
524   {
525       IAM_LOGI("Extension interface, temporarily useless");
526       static_cast<void>(commandId);
527       static_cast<void>(extraInfo);
528       static_cast<void>(callbackObj);
529       return HDF_SUCCESS;
530   }
531   ```
532
533
534### Verification
535Verify whether PIN authentication can be successfully performed on the RK3568 platform as follows:
536
5371. Set a PIN.
538
539    Touch **Settings** > **Biometrics & passwords** > **Password**, and enter your password.
540
5412. Verify PIN authentication.
542
543    1) Press the power button to lock the screen.
544
545    2) Press the power button again, and enter an incorrect password for five consecutive times. The device will be locked for 60 seconds.
546
547    3) Enter the correct password. The screen is unlocked.
548
5493. Disable PIN authentication.
550
551    1) Touch **Settings** > **Biometrics & passwords** > **Password**.
552
553    2) Touch **Disable lock screen password** and **Disable**.
554
5554. Change the PIN.
556
557    1) Touch **Settings** > **Biometrics & passwords** > **Password**.
558
559    2) Touch **Change screen lock password** and set the new password.
560