• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Fingerprint Authentication
2
3## Overview
4
5### Function
6
7Fingerprint authentication is indispensable in identity authentication scenarios, such as device unlocking, payment, and app logins. The fingerprint authentication (Fingerprint_auth) module provides fingerprint authentication for a device after a user enrolls a fingerprint. The figure below shows the fingerprint authentication architecture.
8
9The Fingerprint_auth driver is developed based on the Hardware Driver Foundation (HDF). It shields hardware differences and provides stable fingerprint authentication capabilities for the upper-layer user authentication (User_auth) framework and Fingerprint_auth service. It provides APIs for obtaining the fingerprint authentication executor list, executor information, and template information by template ID, comparing fingerprint template information of the executor and that of User_auth, enrolling or deleting fingerprints, and performing fingerprint authentication.
10
11**Figure 1** Fingerprint authentication architecture
12
13![image](figures/fingerprint_auth_architecture.png "Fingerprint authentication architecture")
14
15### Basic Concepts
16
17The identity authentication consists of the User_auth framework and basic authentication services. It supports basic functions such as setting and deleting user credentials and performing authentication. The system supports user identity authentication and data collection, processing, storage, and comparison.
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 of the runtime environment when an executor provides capabilities.
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- Authentication credential
47
48  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.
49
50- Data verification by the executor
51
52  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.
53
54- HAPs
55
56  In a broad sense, OpenHarmony Ability Packages (HAPs) are application packages that can be installed on OpenHarmony. In this document, the HAPs only refer to the upper-layer applications of the Face_auth driver.
57
58- IDL interface
59
60  An Interface Definition Language (IDL) is a language that lets a program or object written in one language communicate with another program written in an unknown language. An IDL compiler generates client stub files and server framework files. This document describes how to use the client and server generated by the IDL interface to implement communication between the Fingerprint_auth service and driver. For details, see [IDL](https://gitee.com/openharmony/ability_idl_tool/blob/master/README.md).
61
62- IPC
63
64  Inter-process communication (IPC) is a mechanism that allows processes to communicate with each other. For details, see [IPC](https://gitee.com/openharmony/communication_ipc/blob/master/README.md).
65
66- HDI
67
68  The hardware device interface (HDI) is located between the basic system service layer and the device driver layer. It provides APIs for abstracting hardware device functions, which shields underlying hardware device differences for system services. For details, see [HDI Specifications](../../design/hdi-design-specifications.md).
69
70### Working Principles
71
72The fingerprint_auth driver provides stable basic fingerprint authentication capabilities for the upper-layer User_auth framework and Fingerprint_auth service to ensure successful fingerprint authentication on devices. The figure below shows the interaction between the Fingerprint_auth service and the Fingerprint_auth driver. The Fingerprint_auth service obtains executor information by using **GetExecutorInfo()** and registers the executor with the User_auth framework. The Fingerprint_auth service exchanges information with the Fingerprint_auth driver for authentication, identification, and query through the executor APIs.
73You can develop drivers to call Hardware Device Interface (HDI) APIs based on the HDF and the chip you use.
74
75**Figure 2** Interaction between the Fingerprint_auth service and Fingerprint_auth driver
76
77![image](figures/fingerprint_auth_service_and_driver_interaction.png "Fingerprint_auth service and driver interaction")
78
79### Constraints
80
81A Trusted Execution Environment (TEE) must be available on the device to store encrypted fingerprint feature information.
82
83## Development Guidelines
84
85### When to Use
86
87The fingerprint_auth driver provides stable basic fingerprint authentication capabilities for the upper-layer User_auth framework and Fingerprint_auth service to ensure successful fingerprint authentication on devices. To implement the preceding functions, you need to develop the Fingerprint_auth driver based on the HDF, and then implement the APIs for obtaining the executor list and functional APIs such as authentication and query.
88
89### Available APIs
90
91The following table describes the C++ APIs generated from the Interface Definition Language (IDL) interface description. For details about the interface declaration, see the .idl file in **/drivers/interface/fingerprint_auth/**.
92**Table 1** describes the HDI APIs for fingerprint credential enrollment, authentication, recognition, and deletion. **Table 2** describes the callbacks used to return the executor operation result to the framework or return the authentication tip information to upper-layer applications.
93
94**Table 1** Available APIs
95
96| API       | Description        |
97| -------------------------------- | ----------------------------------- |
98| GetExecutorList(std::vector\<sptr\<V1_0::IExecutor>>& executorList)  | Obtains the executor list (version V1_0).|
99| GetExecutorListV1_1(std::vector\<sptr\<V1_1::IExecutor>>& executorList)      | Obtains the executor list (version V1_1).                        |
100| GetExecutorInfo(ExecutorInfo& info)                          | Obtains the executor information, including the executor type, executor role, authentication type, security level, and executor public key.|
101| GetTemplateInfo(uint64_t templateId, TemplateInfo& info)     | Obtains information about the template based on the specified ID.       |
102| OnRegisterFinish(const std::vector\<uint64_t>& templateIdList,<br>        const std::vector\<uint8_t>& frameworkPublicKey, const std::vector\<uint8_t>& extraInfo) | Obtains the public key and template ID list from User_auth after the executor is registered successfully.|
103| Enroll(uint64_t scheduleId, const std::vector\<uint8_t>& extraInfo,<br>        const sptr\<IExecutorCallback>& callbackObj) | Enrolls a fingerprint.                                              |
104| Authenticate(uint64_t scheduleId, const std::vector\<uint64_t>& templateIdList,<br>        const std::vector\<uint8_t>& extraInfo, const sptr\<IExecutorCallback>& callbackObj) | Authenticates a fingerprint (version V1_0).        |
105| AuthenticateV1_1(uint64_t scheduleId, const std::vector\<uint64_t>& templateIdList,<br>        bool endAfterFirstFail, const std::vector\<uint8_t>& extraInfo, const sptr\<IExecutorCallback>& callbackObj) | Authenticates a fingerprint (version V1_1).        |
106| Identify(uint64_t scheduleId, const std::vector\<uint8_t>& extraInfo,<br>        const sptr\<IExecutorCallback>& callbackObj) | Identifies a fingerprint.          |
107| Delete(const std::vector\<uint64_t>& templateIdList)          | Deletes a fingerprint.       |
108| Cancel(uint64_t scheduleId)     | Cancels a fingerprint enrollment, authentication, or identification operation based on the **scheduleId**.    |
109| SendCommand(int32_t commandId, const std::vector\<uint8_t>& extraInfo,<br>        const sptr\<IExecutorCallback>& callbackObj) | Sends commands to the Fingerprint_auth driver.      |
110| GetProperty(const std::vector\<uint64_t>& templateIdList,<br>const std::vector\<GetPropertyType>& propertyTypes, Property& property) | Obtains executor property information.|
111| SetCachedTemplates(const std::vector\<uint64_t> &templateIdList) | Sets a list of templates to be cached.|
112| RegisterSaCommandCallback(const sptr\<ISaCommandCallback> &callbackObj) | Registers a callback to be invoked when an SA command is executed.|
113
114**Table 2** Callbacks
115
116| API                                                      | Description                |
117| ------------------------------------------------------------ | ------------------------ |
118| IExecutorCallback::OnResult(int32_t code, const std::vector\<uint8_t>& extraInfo) | Called to return the operation result.    |
119| IExecutorCallback::OnTip(int32_t code, const std::vector\<uint8_t>& extraInfo) | Called to return the interaction information about the operation process.|
120| ISaCommandCallback::OnSaCommands(const std::vector\<SaCommand>& commands) | Called to send the command list.|
121
122### How to Develop
123
124The following uses the Hi3516D V300 development board as an example to demonstrate how to develop the Fingerprint_auth driver. <br/>The directory structure is as follows:
125
126```undefined
127// drivers/peripheral/fingerprint_auth
128├── BUILD.gn       # Build script
129├── bundle.json    # Component description file
130└── hdi_service    # Fingerprint_auth driver implementation
131    ├── BUILD.gn   # Build script
132    ├── include    # Header files
133    └── src        # Source files
134        ├── executor_impl.cpp                      # Implementation of authentication and enrollment APIs
135        ├── fingerprint_auth_interface_driver.cpp  # Fingerprint_auth driver entry
136        └── fingerprint_auth_interface_service.cpp # Implementation of the API for obtaining the executor list
137```
138
139The development procedure is as follows:
140
1411. Develop the Fingerprint_auth driver based on the HDF using the **Bind()**, **Init()**, **Release()**, and **Dispatch()** functions. For details about the code, see [fingerprint_auth_interface_driver.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/fingerprint_auth/hdi_service/src/fingerprint_auth_interface_driver.cpp).<br>The sample code is as follows:
142
143   ```c++
144   // Create an IRemoteObject object by using the custom HdfFingerprintAuthInterfaceHost object, which consists of the IoService object and HDI service.
145   struct HdfFingerprintAuthInterfaceHost {
146       struct IDeviceIoService ioService;
147       OHOS::sptr<OHOS::IRemoteObject> stub;
148   };
149
150   // Enable the IPC service to call the response API.
151   static int32_t FingerprintAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
152       struct HdfSBuf *reply)
153   {
154       IAM_LOGI("start");
155       auto *hdfFingerprintAuthInterfaceHost = CONTAINER_OF(client->device->service,
156           struct HdfFingerprintAuthInterfaceHost, ioService);
157
158       OHOS::MessageParcel *dataParcel = nullptr;
159       OHOS::MessageParcel *replyParcel = nullptr;
160       OHOS::MessageOption option;
161
162       if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
163           IAM_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__);
164           return HDF_ERR_INVALID_PARAM;
165       }
166       if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
167           IAM_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__);
168           return HDF_ERR_INVALID_PARAM;
169       }
170
171       return hdfFingerprintAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
172   }
173
174   // Initialize the HdfFingerprintAuthInterfaceDriver object.
175   int HdfFingerprintAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
176   {
177       IAM_LOGI("start");
178       if (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_USERAUTH)) {
179           IAM_LOGE("set fingerprint auth hdf class failed");
180           return HDF_FAILURE;
181       }
182       return HDF_SUCCESS;
183   }
184
185   // Bind the service provided by the Fingerprint_auth driver to the HDF.
186   int HdfFingerprintAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
187   {
188       IAM_LOGI("start");
189       auto *hdfFingerprintAuthInterfaceHost = new (std::nothrow) HdfFingerprintAuthInterfaceHost;
190       if (hdfFingerprintAuthInterfaceHost == nullptr) {
191           IAM_LOGE("%{public}s: failed to create HdfFaceAuthInterfaceHost object", __func__);
192           return HDF_FAILURE;
193       }
194
195       hdfFingerprintAuthInterfaceHost->ioService.Dispatch = FingerprintAuthInterfaceDriverDispatch;
196       hdfFingerprintAuthInterfaceHost->ioService.Open = NULL;
197       hdfFingerprintAuthInterfaceHost->ioService.Release = NULL;
198
199       auto serviceImpl = IFingerprintAuthInterface::Get(true);
200       if (serviceImpl == nullptr) {
201           IAM_LOGE("%{public}s: failed to implement service", __func__);
202           return HDF_FAILURE;
203       }
204
205       hdfFingerprintAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
206           IFaceAuthInterface::GetDescriptor());
207       if (hdfFingerprintAuthInterfaceHost->stub == nullptr) {
208           IAM_LOGE("%{public}s: Failed to get stub object", __func__);
209           return HDF_FAILURE;
210       }
211
212       deviceObject->service = &hdfFingerprintAuthInterfaceHost->ioService;
213       IAM_LOGI("success");
214       return HDF_SUCCESS;
215   }
216
217   // Release the resources used by the Fingerprint_auth driver.
218   void HdfFingerprintAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
219   {
220       IAM_LOGI("start");
221       auto *hdfFingerprintAuthInterfaceHost = CONTAINER_OF(deviceObject->service,
222           struct HdfFaceAuthInterfaceHost, ioService);
223       delete hdfFaceAuthInterfaceHost;
224       IAM_LOGI("success");
225   }
226
227   // Register the Fingerprint_auth driver entry data structure object.
228   struct HdfDriverEntry g_fingerprintAuthInterfaceDriverEntry = {
229       .moduleVersion = 1,
230       .moduleName = "fingerprint_auth_interface_service",
231       .Bind = HdfFingerprintAuthInterfaceDriverBind,
232       .Init = HdfFingerprintAuthInterfaceDriverInit,
233       .Release = HdfFingerprintAuthInterfaceDriverRelease,
234   };
235
236   // 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.
237   HDF_INIT(g_fingerprintAuthInterfaceDriverEntry);
238   ```
239
2402. Implement the API for obtaining the executor list. For details about the code, see [fingerprint_auth_interface_service.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/fingerprint_auth/hdi_service/src/fingerprint_auth_interface_service.cpp).<br>The sample code is as follows:
241
242   ```c++
243   // Executor implementation class
244   class ExecutorImpl : public IExecutor {
245   public:
246       ExecutorImpl(struct ExecutorInfo executorInfo);
247       virtual ~ExecutorImpl() {}
248
249   private:
250       struct ExecutorInfo executorInfo_; // Executor information
251   };
252
253   static constexpr uint16_t SENSOR_ID = 123; // Executor sensor ID
254   static constexpr uint32_t EXECUTOR_TYPE = 123; // Executor type
255   static constexpr size_t PUBLIC_KEY_LEN = 32; //32-byte public key of the executor
256
257   // Create an HDI service object.
258   extern "C" IFaceAuthInterface *FingerprintAuthInterfaceImplGetInstance(void)
259   {
260       auto fingerprintAuthInterfaceService = new (std::nothrow) FingerprintAuthInterfaceService();
261       if (fingerprintAuthInterfaceService == nullptr) {
262           IAM_LOGE("faceAuthInterfaceService is nullptr");
263           return nullptr;
264       }
265       return fingerprintAuthInterfaceService;
266   }
267
268   // Obtain the executor list and create an executor.
269   int32_t GetExecutorListV1_1(std::vector<sptr<V1_1::IExecutor>>& executorList)
270   {
271       IAM_LOGI("interface mock start");
272       executorList.clear();
273       struct ExecutorInfo executorInfoExample = {
274           .sensorId = SENSOR_ID,
275           .executorType = EXECUTOR_TYPE,
276           .executorRole = ExecutorRole::ALL_IN_ONE,
277           .authType = AuthType::FINGERPRINT,
278           .esl = ExecutorSecureLevel::ESL0, // Executor security level, which ranges from ESL0 to ESL3 (highest).
279           .publicKey = std::vector<uint8_t>(PUBLIC_KEY_LEN, 0), // 32-byte public key, using the Ed25519 algorithm.
280           .extraInfo = {},
281       };
282       auto executor = new (std::nothrow) ExecutorImpl(executorInfoExample);
283       if (executor == nullptr) {
284           IAM_LOGE("executor is nullptr");
285           return HDF_FAILURE;
286       }
287       executorList.push_back(sptr<V1_1::IExecutor>(executor));
288       IAM_LOGI("interface mock success");
289       return HDF_SUCCESS;
290   }
291
292   // Obtain the executor list. The method of V1_0 is called to invoke the method of V1_1 through parameter conversion.
293   int32_t GetExecutorList(std::vector<sptr<V1_0::IExecutor>> &executorList)
294   {
295       std::vector<sptr<V1_1::IExecutor>> executorListV1_1;
296       int32_t result = GetExecutorListV1_1(executorListV1_1);
297       for (auto &executor : executorListV1_1) {
298           executorList.push_back(executor);
299       }
300       return result;
301   }
302   ```
303
3043. Implement each function of the executor. For details about the code, see [executor_impl.cpp](https://gitee.com/openharmony/drivers_peripheral/blob/master/fingerprint_auth/hdi_service/src/executor_impl.cpp).<br>The sample code is as follows:
305
306   ```c++
307   // Obtain the executor information.
308   int32_t GetExecutorInfo(ExecutorInfo& info)
309   {
310       IAM_LOGI("interface mock start");
311       info = executorInfo_;
312       IAM_LOGI("Executor information got successfully");
313       return HDF_SUCCESS;
314   }
315
316   // Obtain template information based on templateId.
317   int32_t GetTemplateInfo(uint64_t templateId, TemplateInfo& info)
318   {
319       IAM_LOGI("interface mock start");
320       static_cast<void>(templateId);
321       info = {0};
322       IAM_LOGI("Template information got successfully");
323       return HDF_SUCCESS;
324   }
325
326   // After the executor is successfully registered, obtain the public key and template ID list from User_auth and save the public key. The executor compares its template ID list with the template ID list obtained and updates its template ID list.
327   int32_t OnRegisterFinish(const std::vector<uint64_t>& templateIdList,
328       const std::vector<uint8_t>& frameworkPublicKey, const std::vector<uint8_t>& extraInfo)
329   {
330       IAM_LOGI("interface mock start");
331       static_cast<void>(templateIdList);
332       static_cast<void>(extraInfo);
333       static_cast<void>(frameworkPublicKey);
334       IAM_LOGI("registration finished");
335       return HDF_SUCCESS;
336   }
337
338   // Enroll fingerprints.
339   int32_t Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,
340       const sptr<IExecutorCallback>& callbackObj)
341   {
342       IAM_LOGI("interface mock start");
343       static_cast<void>(scheduleId);
344       static_cast<void>(extraInfo);
345       IAM_LOGI("enroll, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT);
346       int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {});
347       if (ret != ResultCode::SUCCESS) {
348           IAM_LOGE("callback result is %{public}d", ret);
349           return HDF_FAILURE;
350       }
351       return HDF_SUCCESS;
352   }
353
354   // Call Authenticate() of V1_0 to invoke authenticate() of V1_1.
355   int32_t Authenticate(uint64_t scheduleId, const std::vector<uint64_t> &templateIdList,
356       const std::vector<uint8_t> &extraInfo, const sptr<IExecutorCallback> &callbackObj)
357   {
358       IAM_LOGI("interface mock start");
359       return AuthenticateV1_1(scheduleId, templateIdList, true, extraInfo, callbackObj);
360   }
361
362   // Call Authenticate() of V1_1 to implement fingerprint authentication.
363   int32_t AuthenticateV1_1(uint64_t scheduleId, const std::vector<uint64_t>& templateIdList, bool endAfterFirstFail,
364       const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj)
365   {
366       IAM_LOGI("interface mock start");
367       static_cast<void>(scheduleId);
368       static_cast<void>(templateIdList);
369       static_cast<void>(endAfterFirstFail);
370       static_cast<void>(extraInfo);
371       IAM_LOGI("authenticateV1_1, result is %{public}d", ResultCode::NOT_ENROLLED);
372       int32_t ret = callbackObj->OnResult(ResultCode::NOT_ENROLLED, {});
373       if (ret != ResultCode::SUCCESS) {
374           IAM_LOGE("callback result is %{public}d", ret);
375           return HDF_FAILURE;
376       }
377       return HDF_SUCCESS;
378   }
379
380   // Identify fingerprints.
381   int32_t Identify(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,
382       const sptr<IExecutorCallback>& callbackObj)
383   {
384       IAM_LOGI("interface mock start");
385       static_cast<void>(scheduleId);
386       static_cast<void>(extraInfo);
387       IAM_LOGI("identify, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT);
388       int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {});
389       if (ret != ResultCode::SUCCESS) {
390           IAM_LOGE("callback result is %{public}d", ret);
391           return HDF_FAILURE;
392       }
393       return HDF_SUCCESS;
394   }
395
396   // Delete fingerprints.
397   int32_t Delete(const std::vector<uint64_t>& templateIdList)
398   {
399       IAM_LOGI("interface mock start");
400       static_cast<void>(templateIdList);
401       IAM_LOGI("delete success");
402       return HDF_SUCCESS;
403   }
404
405   // Cancel the operation based on the specified scheduleId.
406   int32_t Cancel(uint64_t scheduleId)
407   {
408       IAM_LOGI("interface mock start");
409       static_cast<void>(scheduleId);
410       IAM_LOGI("cancel success");
411       return HDF_SUCCESS;
412   }
413
414   // Send template locking or unlocking command from the Fingerprint_auth service to the Fingerprint_auth driver.
415   int32_t SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,
416       const sptr<IExecutorCallback>& callbackObj)
417   {
418       IAM_LOGI("interface mock start");
419       static_cast<void>(extraInfo);
420       int32_t ret;
421       switch (commandId) {
422           case LOCK_TEMPLATE:
423               IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS);
424               ret = callbackObj->OnResult(ResultCode::SUCCESS, {});
425               if (ret != ResultCode::SUCCESS) {
426                   IAM_LOGE("callback result is %{public}d", ret);
427                   return HDF_FAILURE;
428               }
429               break;
430           case UNLOCK_TEMPLATE:
431               IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS);
432               ret = callbackObj->OnResult(ResultCode::SUCCESS, {});
433               if (ret != ResultCode::SUCCESS) {
434                   IAM_LOGE("callback result is %{public}d", ret);
435                   return HDF_FAILURE;
436               }
437               break;
438           default:
439               IAM_LOGD("not support CommandId : %{public}d", commandId);
440               ret = callbackObj->OnResult(ResultCode::GENERAL_ERROR, {});
441               if (ret != ResultCode::SUCCESS) {
442                   IAM_LOGE("callback result is %{public}d", ret);
443                   return HDF_FAILURE;
444               }
445       }
446       return HDF_SUCCESS;
447   }
448
449   // Obtain executor properties.
450   int32_t ExecutorImpl::GetProperty(
451       const std::vector<uint64_t> &templateIdList, const std::vector<GetPropertyType> &propertyTypes, Property &property)
452   {
453       IAM_LOGI("interface mock start");
454       property = {};
455       IAM_LOGI("get property success");
456       return HDF_SUCCESS;
457   }
458
459   // Set a list of templates to be cached.
460   int32_t ExecutorImpl::SetCachedTemplates(const std::vector<uint64_t> &templateIdList)
461   {
462       IAM_LOGI("interface mock start");
463       IAM_LOGI("set cached templates success");
464       return HDF_SUCCESS;
465   }
466
467   // Register the callback to be invoked when the SA command is executed.
468   int32_t ExecutorImpl::RegisterSaCommandCallback(const sptr<ISaCommandCallback> &callbackObj)
469   {
470       IAM_LOGI("interface mock start");
471       IAM_LOGI("register sa command callback success");
472       return HDF_SUCCESS;
473   }
474   ```
475
4764. Modify **serviceName2Config** in the **fingerprint_auth_service.cpp** file if you need to add a driver or modify driver information.
477
478   ```c++
479   // base/user_iam/fingerprint_auth/services/src/fingerprint_auth_service.cpp
480   void FingerprintAuthService::StartDriverManager()
481   {
482       IAM_LOGI("start");
483       // Service name and ID of the driver to add or modify. The driver service name and ID must be globally unique.
484       const std::map<std::string, UserAuth::ServiceConfig> serviceName2Config = {
485           {"fingerprint_auth_interface_service", {2, std::make_shared<FingerprintAuthDriverHdi>()}},
486       };
487       UserIAM::UserAuth::IDriverManager::GetInstance().Start(serviceName2Config);
488   }
489   ```
490
491### Verification
492
493Use the [User Authentication APIs](../../application-dev/reference/apis/js-apis-useriam-userauth.md) to develop a JavaScript application and verify the application on the Hi3516D V300 development board. The JavaScript application invokes the Fingerprint_auth driver via the Fingerprint_auth service. The sample code is as follows:
494
495    ```js
496    // API version 9
497    import userIAM_userAuth from '@ohos.userIAM.userAuth';
498
499    let challenge = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8]);
500    let authType = userIAM_userAuth.UserAuthType.FINGERPRINT;
501    let authTrustLevel = userIAM_userAuth.AuthTrustLevel.ATL1;
502
503    // Obtain an authentication object.
504    let auth;
505    try {
506        auth = userIAM_userAuth.getAuthInstance(challenge, authType, authTrustLevel);
507        console.log("get auth instance success");
508    } catch (error) {
509        console.log("get auth instance failed" + error);
510    }
511
512    // Subscribe to the authentication result.
513    try {
514        auth.on("result", {
515            callback: (result: userIAM_userAuth.AuthResultInfo) => {
516                console.log("authV9 result " + result.result);
517                console.log("authV9 token " + result.token);
518                console.log("authV9 remainAttempts " + result.remainAttempts);
519                console.log("authV9 lockoutDuration " + result.lockoutDuration);
520            }
521        });
522        console.log("subscribe authentication event success");
523    } catch (error) {
524        console.log("subscribe authentication event failed " + error);
525    }
526
527    // Start user authentication.
528    try {
529        auth.start();
530        console.info("authV9 start auth success");
531    } catch (error) {
532        console.info("authV9 start auth failed, error = " + error);
533    }
534
535    // Cancel the authentication.
536    try {
537        auth.cancel();
538        console.info("cancel auth success");
539    } catch (error) {
540        console.info("cancel auth failed, error = " + error);
541    }
542
543    // Unsubscribe from the authentication result.
544    try {
545        auth.off("result");
546        console.info("cancel subscribe authentication event success");
547    } catch (error) {
548        console.info("cancel subscribe authentication event failed, error = " + error);
549    }
550    ```
551