• 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 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- 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  OpenHarmony Ability Packages (HAPs) represent the upper-layer applications of the Fingerprint_auth driver in this document.
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. In this document, the IDL interface implements communication between the Fingerprint_auth service and the driver.
61
62- IPC
63
64  Inter-Process Communication (IPC) is a mechanism that allows processes to communicate with each other.
65
66### Working Principles
67
68The 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.
69
70The figure below shows the interaction between the Fingerprint_auth service and the Fingerprint_auth driver.
71
72The Fingerprint_auth service obtains the 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
91**Table 1** Available APIs
92
93| API                                                      | Description                                                    |
94| ------------------------------------------------------------ | ------------------------------------------------------------ |
95| GetExecutorList(std::vector<sptr<IExecutor>>& executorList)  | Obtains the executor list.                                            |
96| GetExecutorInfo(ExecutorInfo& info)                          | Obtains the executor information, including the executor type, executor role, authentication type, security level, and executor public key.|
97| GetTemplateInfo(uint64_t templateId, TemplateInfo& info)     | Obtains information about the template based on the specified ID.                                  |
98| 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.|
99| Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,<br>        const sptr<IExecutorCallback>& callbackObj) | Enrolls a fingerprint template.                                              |
100| Authenticate(uint64_t scheduleId, const std::vector<uint64_t>& templateIdList,<br>        const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj) | Authenticates a fingerprint template.                                              |
101| Identify(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,<br>        const sptr<IExecutorCallback>& callbackObj) | Identifies a fingerprint template.                                              |
102| Delete(const std::vector<uint64_t>& templateIdList)          | Deletes a fingerprint template.                                              |
103| Cancel(uint64_t scheduleId)                                  | Cancels a fingerprint enrolling, authentication, or identification operation based on the **scheduleId**.                |
104| SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,<br>        const sptr<IExecutorCallback>& callbackObj) | Sends commands to the Fingerprint_auth driver.      |
105
106**Table 2** Callbacks
107
108| API                                                      | Description                |
109| ------------------------------------------------------------ | ------------------------ |
110| IExecutorCallback::OnResult(int32_t code, const std::vector<uint8_t>& extraInfo) | Called to return the operation result.    |
111| IExecutorCallback::OnTip(int32_t code, const std::vector<uint8_t>& extraInfo) | Called to return the interaction information about the operation process.|
112
113### How to Develop
114
115The 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:
116
117```undefined
118// drivers/peripheral/fingerprint_auth
119├── BUILD.gn            # Build script
120├── bundle.json         # Module description file
121└── hdi_service         # Fingerprint_auth driver implementation
122    ├── BUILD.gn        # Build script
123    ├── include         # Header files
124    └── src
125        ├── executor_impl.cpp                      # Implementation of authentication and enrollment APIs
126        ├── fingerprint_auth_interface_driver.cpp  # Fingerprint_auth driver entry
127        └── fingerprint_auth_interface_service.cpp # Implementation of the API for obtaining the executor list
128```
129
130The development procedure is as follows:
131
1321. 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:
133
134   ```c++
135   // Create an IRemoteObject object by using the custom HdfFingerprintAuthInterfaceHost object, which consists of the IoService object and HDI service.
136   struct HdfFingerprintAuthInterfaceHost {
137       struct IDeviceIoService ioService;
138       OHOS::sptr<OHOS::IRemoteObject> stub;
139   };
140
141   // Enable the IPC service to call the response API.
142   static int32_t FingerprintAuthInterfaceDriverDispatch(struct HdfDeviceIoClient *client, int cmdId, struct HdfSBuf *data,
143       struct HdfSBuf *reply)
144   {
145       IAM_LOGI("start");
146       auto *hdfFingerprintAuthInterfaceHost = CONTAINER_OF(client->device->service,
147           struct HdfFingerprintAuthInterfaceHost, ioService);
148
149       OHOS::MessageParcel *dataParcel = nullptr;
150       OHOS::MessageParcel *replyParcel = nullptr;
151       OHOS::MessageOption option;
152
153       if (SbufToParcel(data, &dataParcel) != HDF_SUCCESS) {
154           IAM_LOGE("%{public}s:invalid data sbuf object to dispatch", __func__);
155           return HDF_ERR_INVALID_PARAM;
156       }
157       if (SbufToParcel(reply, &replyParcel) != HDF_SUCCESS) {
158           IAM_LOGE("%{public}s:invalid reply sbuf object to dispatch", __func__);
159           return HDF_ERR_INVALID_PARAM;
160       }
161
162       return hdfFingerprintAuthInterfaceHost->stub->SendRequest(cmdId, *dataParcel, *replyParcel, option);
163   }
164
165   // Initialize the HdfFingerprintAuthInterfaceDriver object.
166   int HdfFingerprintAuthInterfaceDriverInit(struct HdfDeviceObject *deviceObject)
167   {
168       IAM_LOGI("start");
169       if (!HdfDeviceSetClass(deviceObject, DEVICE_CLASS_USERAUTH)) {
170           IAM_LOGE("set fingerprint auth hdf class failed");
171           return HDF_FAILURE;
172       }
173       return HDF_SUCCESS;
174   }
175
176   // Bind the service provided by the Fingerprint_auth driver to the HDF.
177   int HdfFingerprintAuthInterfaceDriverBind(struct HdfDeviceObject *deviceObject)
178   {
179       IAM_LOGI("start");
180       auto *hdfFingerprintAuthInterfaceHost = new (std::nothrow) HdfFingerprintAuthInterfaceHost;
181       if (hdfFingerprintAuthInterfaceHost == nullptr) {
182           IAM_LOGE("%{public}s: failed to create HdfFaceAuthInterfaceHost object", __func__);
183           return HDF_FAILURE;
184       }
185
186       hdfFingerprintAuthInterfaceHost->ioService.Dispatch = FingerprintAuthInterfaceDriverDispatch;
187       hdfFingerprintAuthInterfaceHost->ioService.Open = NULL;
188       hdfFingerprintAuthInterfaceHost->ioService.Release = NULL;
189
190       auto serviceImpl = IFingerprintAuthInterface::Get(true);
191       if (serviceImpl == nullptr) {
192           IAM_LOGE("%{public}s: failed to implement service", __func__);
193           return HDF_FAILURE;
194       }
195
196       hdfFingerprintAuthInterfaceHost->stub = OHOS::HDI::ObjectCollector::GetInstance().GetOrNewObject(serviceImpl,
197           IFaceAuthInterface::GetDescriptor());
198       if (hdfFingerprintAuthInterfaceHost->stub == nullptr) {
199           IAM_LOGE("%{public}s: Failed to get stub object", __func__);
200           return HDF_FAILURE;
201       }
202
203       deviceObject->service = &hdfFingerprintAuthInterfaceHost->ioService;
204       IAM_LOGI("success");
205       return HDF_SUCCESS;
206   }
207
208   // Release the resources used by the Fingerprint_auth driver.
209   void HdfFingerprintAuthInterfaceDriverRelease(struct HdfDeviceObject *deviceObject)
210   {
211       IAM_LOGI("start");
212       auto *hdfFingerprintAuthInterfaceHost = CONTAINER_OF(deviceObject->service,
213           struct HdfFaceAuthInterfaceHost, ioService);
214       delete hdfFaceAuthInterfaceHost;
215       IAM_LOGI("success");
216   }
217
218   // Register the Fingerprint_auth driver entry data structure object.
219   struct HdfDriverEntry g_fingerprintAuthInterfaceDriverEntry = {
220       .moduleVersion = 1,
221       .moduleName = "fingerprint_auth_interface_service",
222       .Bind = HdfFingerprintAuthInterfaceDriverBind,
223       .Init = HdfFingerprintAuthInterfaceDriverInit,
224       .Release = HdfFingerprintAuthInterfaceDriverRelease,
225   };
226
227   // 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.
228   HDF_INIT(g_fingerprintAuthInterfaceDriverEntry);
229   ```
230
2312. 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:
232
233   ```c++
234   // Executor implementation class
235   class ExecutorImpl : public IExecutor {
236   public:
237       ExecutorImpl(struct ExecutorInfo executorInfo);
238       virtual ~ExecutorImpl() {}
239
240   private:
241       struct ExecutorInfo executorInfo_; // Executor information
242   };
243
244   static constexpr uint16_t SENSOR_ID = 123; // Executor sensor ID
245   static constexpr uint32_t EXECUTOR_TYPE = 123; // Executor type
246   static constexpr size_t PUBLIC_KEY_LEN = 32; //32-byte public key of the executor
247
248   // Create an HDI service object.
249   extern "C" IFaceAuthInterface *FingerprintAuthInterfaceImplGetInstance(void)
250   {
251       auto fingerprintAuthInterfaceService = new (std::nothrow) FingerprintAuthInterfaceService();
252       if (fingerprintAuthInterfaceService == nullptr) {
253           IAM_LOGE("faceAuthInterfaceService is nullptr");
254           return nullptr;
255       }
256       return fingerprintAuthInterfaceService;
257   }
258
259   // Obtain the executor list and create an executor.
260   int32_t GetExecutorList(std::vector<sptr<IExecutor>>& executorList)
261   {
262       IAM_LOGI("interface mock start");
263       executorList.clear();
264       struct ExecutorInfo executorInfoExample = {
265           .sensorId = SENSOR_ID,
266           .executorType = EXECUTOR_TYPE,
267           .executorRole = ExecutorRole::ALL_IN_ONE,
268           .authType = AuthType::FINGERPRINT,
269           .esl = ExecutorSecureLevel::ESL0, // Executor security level, which ranges from ESL0 to ESL3 (highest).
270           .publicKey = std::vector<uint8_t>(PUBLIC_KEY_LEN, 0), // 32-byte public key, using the Ed25519 algorithm.
271           .extraInfo = {},
272       };
273       auto executor = new (std::nothrow) ExecutorImpl(executorInfoExample);
274       if (executor == nullptr) {
275           IAM_LOGE("executor is nullptr");
276           return HDF_FAILURE;
277       }
278       executorList.push_back(sptr<IExecutor>(executor));
279       IAM_LOGI("interface mock success");
280       return HDF_SUCCESS;
281   }
282   ```
283
2843. 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:
285
286   ```c++
287   // Obtain the executor information.
288   int32_t GetExecutorInfo(ExecutorInfo& info)
289   {
290       IAM_LOGI("interface mock start");
291       info = executorInfo_;
292       IAM_LOGI("Executor information got successfully");
293       return HDF_SUCCESS;
294   }
295
296   // Obtain template information based on templateId.
297   int32_t GetTemplateInfo(uint64_t templateId, TemplateInfo& info)
298   {
299       IAM_LOGI("interface mock start");
300       static_cast<void>(templateId);
301       info = {0};
302       IAM_LOGI("Template information got successfully");
303       return HDF_SUCCESS;
304   }
305
306   // 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.
307   int32_t OnRegisterFinish(const std::vector<uint64_t>& templateIdList,
308       const std::vector<uint8_t>& frameworkPublicKey, const std::vector<uint8_t>& extraInfo)
309   {
310       IAM_LOGI("interface mock start");
311       static_cast<void>(templateIdList);
312       static_cast<void>(extraInfo);
313       static_cast<void>(frameworkPublicKey);
314       IAM_LOGI("registration finished");
315       return HDF_SUCCESS;
316   }
317
318   // Enroll fingerprints.
319   int32_t Enroll(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,
320       const sptr<IExecutorCallback>& callbackObj)
321   {
322       IAM_LOGI("interface mock start");
323       static_cast<void>(scheduleId);
324       static_cast<void>(extraInfo);
325       IAM_LOGI("enroll, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT);
326       int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {});
327       if (ret != ResultCode::SUCCESS) {
328           IAM_LOGE("callback result is %{public}d", ret);
329           return HDF_FAILURE;
330       }
331       return HDF_SUCCESS;
332   }
333
334   // Authenticate fingerprints.
335   int32_t Authenticate(uint64_t scheduleId, const std::vector<uint64_t>& templateIdList,
336       const std::vector<uint8_t>& extraInfo, const sptr<IExecutorCallback>& callbackObj)
337   {
338       IAM_LOGI("interface mock start");
339       static_cast<void>(scheduleId);
340       static_cast<void>(templateIdList);
341       static_cast<void>(extraInfo);
342       IAM_LOGI("authenticate, result is %{public}d", ResultCode::NOT_ENROLLED);
343       int32_t ret = callbackObj->OnResult(ResultCode::NOT_ENROLLED, {});
344       if (ret != ResultCode::SUCCESS) {
345           IAM_LOGE("callback result is %{public}d", ret);
346           return HDF_FAILURE;
347       }
348       return HDF_SUCCESS;
349   }
350
351   // Identify fingerprints.
352   int32_t Identify(uint64_t scheduleId, const std::vector<uint8_t>& extraInfo,
353       const sptr<IExecutorCallback>& callbackObj)
354   {
355       IAM_LOGI("interface mock start");
356       static_cast<void>(scheduleId);
357       static_cast<void>(extraInfo);
358       IAM_LOGI("identify, result is %{public}d", ResultCode::OPERATION_NOT_SUPPORT);
359       int32_t ret = callbackObj->OnResult(ResultCode::OPERATION_NOT_SUPPORT, {});
360       if (ret != ResultCode::SUCCESS) {
361           IAM_LOGE("callback result is %{public}d", ret);
362           return HDF_FAILURE;
363       }
364       return HDF_SUCCESS;
365   }
366
367   // Delete a fingerprint template.
368   int32_t Delete(const std::vector<uint64_t>& templateIdList)
369   {
370       IAM_LOGI("interface mock start");
371       static_cast<void>(templateIdList);
372       IAM_LOGI("delete success");
373       return HDF_SUCCESS;
374   }
375
376   // Cancel the operation based on the specified scheduleId.
377   int32_t Cancel(uint64_t scheduleId)
378   {
379       IAM_LOGI("interface mock start");
380       static_cast<void>(scheduleId);
381       IAM_LOGI("cancel success");
382       return HDF_SUCCESS;
383   }
384
385   // Send template locking or unlocking command from the Fingerprint_auth service to the Fingerprint_auth driver.
386   int32_t SendCommand(int32_t commandId, const std::vector<uint8_t>& extraInfo,
387       const sptr<IExecutorCallback>& callbackObj)
388   {
389       IAM_LOGI("interface mock start");
390       static_cast<void>(extraInfo);
391       int32_t ret;
392       switch (commandId) {
393           case LOCK_TEMPLATE:
394               IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS);
395               ret = callbackObj->OnResult(ResultCode::SUCCESS, {});
396               if (ret != ResultCode::SUCCESS) {
397                   IAM_LOGE("callback result is %{public}d", ret);
398                   return HDF_FAILURE;
399               }
400               break;
401           case UNLOCK_TEMPLATE:
402               IAM_LOGI("unlock template, result is %{public}d", ResultCode::SUCCESS);
403               ret = callbackObj->OnResult(ResultCode::SUCCESS, {});
404               if (ret != ResultCode::SUCCESS) {
405                   IAM_LOGE("callback result is %{public}d", ret);
406                   return HDF_FAILURE;
407               }
408               break;
409           default:
410               IAM_LOGD("not support CommandId : %{public}d", commandId);
411               ret = callbackObj->OnResult(ResultCode::GENERAL_ERROR, {});
412               if (ret != ResultCode::SUCCESS) {
413                   IAM_LOGE("callback result is %{public}d", ret);
414                   return HDF_FAILURE;
415               }
416       }
417       return HDF_SUCCESS;
418   }
419   ```
420
4214. Modify **serviceName2Config** in the **fingerprint_auth_service.cpp** file if you need to add a driver or modify driver information.
422
423   ```c++
424   // base/user_iam/fingerprint_auth/services/src/fingerprint_auth_service.cpp
425   void FingerprintAuthService::StartDriverManager()
426   {
427       IAM_LOGI("start");
428       // Service name and ID of the driver to add or modify. The driver service name and ID must be globally unique.
429       const std::map<std::string, UserAuth::ServiceConfig> serviceName2Config = {
430           {"fingerprint_auth_interface_service", {2, std::make_shared<FingerprintAuthDriverHdi>()}},
431       };
432       UserIAM::UserAuth::IDriverManager::GetInstance().Start(serviceName2Config);
433   }
434   ```
435
436### Verification
437
438Use 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.
439
440The sample code is as follows:
441
442```js
443// API version 8
444import userIAM_userAuth from '@ohos.userIAM.userAuth';
445let auth = new userIAM_userAuth.UserAuth();
446
447export default {
448    getVersion() {
449        console.info("start to get version");
450        let version = this.auth.getVersion();
451        console.info("auth version = " + version);
452    },
453
454    startAuth() {
455        console.info("start auth");
456        // auth is an API that can be called. You can set the authentication type to FINGERPRINT to check whether the driver is successfully registered with the framework and whether the authentication APIs are implemented as expected. result holds the authentication result.
457        this.auth.auth(null, userIAM_userAuth.UserAuthType.FINGERPRINT, userIAM_userAuth.AuthTrustLevel.ATL1, {
458            onResult: (result, extraInfo) => {
459                try {
460                    console.info("auth onResult result = " + result);
461                    console.info("auth onResult extraInfo = " + JSON.stringify(extraInfo));
462                    if (result == userIAM_userAuth.ResultCode.SUCCESS) {
463                        // Add the logic to be executed when the authentication is successful.
464                    }  else {
465                        // Add the logic to be executed when the authentication fails.
466                    }
467                } catch (e) {
468                    console.info("auth onResult error = " + e);
469                }
470            },
471
472            onAcquireInfo: (module, acquire, extraInfo) => {
473                try {
474                    console.info("auth onAcquireInfo module = " + module);
475                    console.info("auth onAcquireInfo acquire = " + acquire);
476                    console.info("auth onAcquireInfo extraInfo = " + JSON.stringify(extraInfo));
477                } catch (e) {
478                    console.info("auth onAcquireInfo error = " + e);
479                }
480            }
481        });
482    }
483}
484```
485