biod
: Biometrics Daemonbiod
(Biometrics Daemon) is a daemon for enrolling, authenticating and managing biometrics data for faster unlocking. It manages all biometric sensors for all users of the device.
Record: specific piece of biometric data that a user registers along with its metadata.
Enroll: the act of registering a record.
EnrollSession: the session during which enrolling of a record happens.
Authenticate: the act of checking a new piece of biometric data against stored records.
AuthSession: the session during which authenticating a new piece of biometric data against stored records happens.
BiometricsManager: manager for a piece of device/hardware/sensor for collecting a specific type of biometric data. Each BiometricsManager
is in charge of storing the records that it enrolled.
For more context, see the Chromium OS Developer Guide.
Start working on the biod
package:
(chroot) $ cros_workon-<board> start biod
Build biod
:
(chroot) $ emerge-<board> biod
Deploy biod
to your DUT
:
(chroot) $ cros deploy ${DUT_IP_ADDR} biod
As a shortcut, you can also scp
the biod
binary to your DUT.
biod
is controlled by upstart
.
(dut)$ start biod
(dut)$ stop biod
(dut)$ status biod
biod
's logs are written to /var/log/biod/biod.LATEST
.
The unit tests can be run with the following command:
(chroot)$ FEATURES=test emerge-<board> biod
You can add and remove fingerprints from the UI by navigating to chrome://os-settings
in Chrome and searching for “fingerprint” in the search bar. Selecting the “Fingerprint settings” option will load the page for adding and removing fingerprints.
The records are stored under the directory: /home/root/[hash_of_user_id]/biod/[name_of_biometrics_manager]/
with the file name: Record[UUID]
.
UUID has the form of XXXXXXXX_XXXX_XXXX_XXXX_XXXXXXXXXXXX
where X
represents a lowercase hex digit. UUID is a 128-bit random number generated with guid
, so it is highly unlikely to repeat. _
are used instead of -
because this UUID is used in biod D-bus object paths, which do not allow -
.
Each record file is stored in JSON format, and contains one record and its record id and label.
The bio_fw_updater
tool is responsible for updating the FPMCU firmware
automatically on boot. The updater checks to see if the firmware binary in /opt/google/biod/fw
matches the firmware that is flashed on the FPMCU and performs an update if the two do not match. Note that it does not consider whether the version of the firmware is semantically “newer”; it's strictly checking for an exact version match.
To disable the automatic update, you can create the .disable_fp_updater
file in the stateful partition:
(dut) $ touch /var/lib/bio_fw_updater/.disable_fp_updater
For security reasons this will work only when we are allowed to boot developer mode from unsigned kernels (crossystem dev_boot_signed_only
reports 0).
When hardware and software write protect for the FPMCU are enabled, bio_fw_updater
will only update the RW portion of the firmware.
When devices are still under development, they will generally have hardware write protect enabled, but not software write protect. In this mode, bio_fw_updater
will update both RO and RW.
You can learn more about write protection and how to enable/disable in the Firmware Write Protection documentation.
bio_fw_updater
's logs are written to:
/var/log/biod/bio_fw_updater.LATEST
/var/log/biod/bio_fw_updater.PREVIOUS
/var/log/biod/bio_fw_updater.<TIMESTAMP>
/var/log/bio_fw_updater.out
CrosFpBiometric (fingerprint MCU) runs the firmware for image capture, matching and enrollment. Biod (cros_fp_biometrics_manager.cc
) interacts with the MCU by doing system calls on /dev/cros_fp
.
On receiving an Authentication request, biod makes a ioctl call to put the MCU in FP_MODE_MATCH. It then listens for MBKP events from the MCU. On receiving the event, based on the result, biod either reports success or failure to the D-bus client (typically Chrome).
Things get little complicated on devices with fingerprint overlapped on power button. On these devices, we need to be careful not to interpret user's interaction with power button as an intent to authenticate via fingerprint. To avoid such scenarios, we ignore fingerprint matches if we have seen a power button event in last few milliseconds. To achieve this, biod keeps track of power button events (power_button_filter.cc
) by listening to d-bus events advertised by powerd (power_manager.cc
). The sequence diagram below gives a sequence of events on devices with fingerprint overlapped on power button.
Biod communicates with Chrome via D-bus messages. Chrome provides the graphical interface for users to enroll new biometric data and manage their own records. Chrome is also responsible for the visual display during authentication.
When a user logs in or biod starts, biod will ask login manager for a list of currently logged-in users, and load from storage the records of the newly logged-in users.
When a user logs out, all users log out at the same time, biod receives a signal from login manager and remove all records in the memory.
Because the records are stored in per user stateful under /home/root/[hash_of_user_id]
, they are naturally encrypted by cryptohome. Records are encrypted when the users log out and decrypted when the users log in. Cryptohome provides a layer of security to biod.
biod_client_tool
provides the interface to fake the behavior of a biometrics client, for example, a lock screen or a biometric enrollment app. It can be used to test biod and biometric sensors. Use the --help
flag to see the options.
Service Name: org.chromium.BiometricsDaemon
Root Object: /org/chromium/BiometricsDaemon
The root object implements the org.freedesktop.DBus.ObjectManager
interface which should be used to enumerate the available biometric devices. Each biometric device implements the org.chromium.BiometricsDaemon.BiometricsManager
interface, which is used to retrieve previously made records or to start an Enroll
or Authenticate
session. Enroll
sessions are for making new records. Authenticate
sessions are for authenticating scanned biometric data against those previously made records. Each session object can be used to end the session, but signals still go through the BiometricsManager object to avoid a race condition between starting a session and connecting to the session‘s signals. Something to note about the session objects is that they will automatically be ended when the D-Bus client that created them (whomever called StartEnrollSession
or StartAuthSession
). This is to prevent the BiometricsManager
from entering a stuck state in case the client crashes and nobody comes around to end the session. This shouldn’t be an issue unless one expects the session to continue after the D-Bus client disconnects, for example while testing out biod
using dbus-send
or other single shot command line dbus tool. Each BiometricsManager
can have only one session running concurrently.
StartEnrollSession(in STRING user_id, in STRING label, out OBJECTPATH enroll_session)
user_id
refers to the sanitized user name returned by SanitizeUserName in libbrillo.
label
is an arbitrary string chosen to be human readable by the user.
The returned enroll_session
object path implements the org.chromium.BiometricsDaemon.EnrollSession
interface, but EnrollScanDone
and SessionFailed
signals still come from this BiometricsManager
.
GetRecords(out ARRAY<OBJECTPATH> records)
Each returned object path implements the org.chromium.BiometricsDaemon.Record
interface.
DestroyAllRecords()
StartAuthSession(out OBJECTPATH auth_session)
The returned object path implements the org.chromium.BiometricsDaemon.AuthSession
interface, but AuthScanDone
and SessionFailed
signals still come from this BiometricsManager
.
EnrollScanDone(UINT32 scan_result, BOOL complete)
If complete
is true, the enrollment was successfully finished and saved.
The UINT32 scan_result
values are meant to be instructions to the user on how to get a better scan. They are as follows:
Note: Pretty much ripped off from AOSP's fingerprint_acquired_info
in fingerprint.h. Codes which are greater or equal to 10000 are ChromeOS specific codes.
AuthScanDone(FingerprintMessage message, std::unordered_map<std::string, std::vector<std::string>> matches)
The returned message
is a protobuf which is the union of ScanResult enum and FingerprintError enum. ScanResult is used to give user a feedback about scanning. FingerprintError is used to provide more details when matching fails but is's not related to user.
Note: Codes for FingerprintError comes from AOSP's fingerprint_error
in fingerprint.h. Codes which are greater or equal to 10000 are ChromeOS specific codes.
The returned matches
are a map from user id to a list of biometric record ids. The user ids are the same ones given to StartEnrollSession
in previous enroll sessions. Each user in the list have one or more records that indicate a match. Note that a piece of biometric data could be registered multiple times under the same or different users.
SessionFailed()
General failure of enroll session and/or authenticate session that can not be recovered from
StatusChanged(BiometricsManagerStatusChanged status)
The signal is emitted when status of Biometrics Manager changes. It contains a status
protobuf which contains BiometricsManagerStatus enum.
The enum contains following entries:
UINT32 Type
Type
has one of the following values:
End()
Ends the authentication session and destroys this object path. Generally, the client should call this at some point because authentication sessions do not end on their own, unless there is some error.
Cancel()
Ends the enroll session without storing the enrollment and destroys this object path. Generally, the client should not call this as the Enroll session will end automatically once enough data is collected. Exceptions to this rule being that there was some error on the client side, the user explicitly canceled the session, or the client has determined the user to have given up, perhaps after some timeout has elapsed.
Remove()
Deletes this record object from memory and persistent storage. It will no longer participate in any future Authenticate sessions.
SetLabel(in STRING label)
Sets the human readable label of this Record
object.
STRING Label
Read-only property that gets the previously set (by either StartEnrollSession
or SetLabel
) human readable label of this record object.
The symbol <-
means Chrome sends the command to org.chromium.BiometricsDaemon
The symbol ->
is either a response or a signal from org.chromium.BiometricsDaemon
Logged in user clicks enroll in UI:
<- Object:/org/chromium/BiometricsDaemon Method:org.freedesktop.DBus.ObjectManager.GetManagedObjects -> [ "/org/chromium/BiometricsDaemon/BiometricsManager0" ] <- Object:/org/chromium/BiometricsDaemon/BiometricsManager0 Method:org.chromium.BiometricsDaemon.BiometricsManager.StartEnrollSession "<user id hash>" "Data 1" -> "/org/chromium/BiometricsDaemon/BiometricsManager0/EnrollSession"
User presses finger onto sensor
-> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Success) false
Chrome UI shows encouraging message about that scan to user
User presses finger again but too quickly
-> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Too Fast) false
Chrome UI shows a stern message about how the user's finger is too fast.
[...] Continued until biod determines there is enough data
-> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Success) true
Chrome displays successful enrollment message
Logged in user locks screen
<- Object:/org/chromium/BiometricsDaemon/BiometricsManager0 Method:org.chromium.BiometricsDaemon.BiometricsManager.StartAuthSession -> /org/chromium/BiometricsDaemon/BiometricsManager0/AuthSession
User does a scan with dirty sensor and lock screen informs the user of this
-> org.chromium.BiometricsDaemon.BiometricsManager.AuthScanDone (Sensor Dirty) [empty array]
User cleans sensor and tries again with success
-> org.chromium.BiometricsDaemon.BiometricsManager.AuthScanDone (Success) ["unordered_map<string user_id, vector<string record_id>>"]
Lock screen lets user in