biod: Biometrics Daemon

biod (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.

Keywords

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.

Building

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.

Running

biod is controlled by upstart.

Start biod

(dut)$ start biod

Stop biod

(dut)$ stop biod

Check whether biod is running

(dut)$ status biod

Logs

biod's logs are written to /var/log/biod/biod.LATEST.

Unit Tests

The unit tests can be run with the following command:

(chroot)$ FEATURES=test emerge-<board> biod

Manual Testing

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.

Storage

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.

Firmware Updates

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.

Logs

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

Hardware

CrosFpBiometric

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.

Authentication

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.

sequence diagram on devices with fp on power button

Enrollment

TODO

Chrome

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.

Login Manager

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.

Cryptohome

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.

Testing Tools

biod_client_tool

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.

D-Bus API

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.

org.chromium.BiometricsDaemon.BiometricsManager

StartEnrollSession (Method)

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 (Method)

GetRecords(out ARRAY<OBJECTPATH> records)

Each returned object path implements the org.chromium.BiometricsDaemon.Record interface.

DestroyAllRecords (Method)

DestroyAllRecords()

StartAuthSession (Method)

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 (Signal)

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.

  • 0 = Success (the sensor captured good data)
  • 1 = Partial (sensor needs more data)
  • 2 = Insufficient (too little detail for recognition)
  • 3 = Sensor Dirty
  • 4 = Too Slow (tell user to speed up)
  • 5 = Too Fast (tell user to slow down)
  • 6 = Immobile (tell user to move a little to get more data)
  • 10000 = No Match (tell user to use another finger, used during authentication)

AuthScanDone (Signal)

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.

  • 1 = HW Unavailable (general hardware error)
  • 2 = Unable To Process (operation can't continue)
  • 3 = Timeout (operation has timed out waiting for user input)
  • 4 = No Space (no space to store the template)
  • 5 = Canceled (operation can't proceed)
  • 6 = Unable To Remove (fingerprint with given ID can't be removed)
  • 7 = Lockout (hardware is locked due to too many attempts)
  • 10000 = No Templates (fingerprint hardware contains no templates)

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 (Signal)

SessionFailed()

General failure of enroll session and/or authenticate session that can not be recovered from

StatusChanged (Signal)

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:

  • 1 = Initialized (ready for Enroll/Auth Session)

Type (Property)

UINT32 Type

Type has one of the following values:

  • 0 = Unknown
  • 1 = Fingerprint

org.chromium.BiometricsDaemon.AuthSession

End (Method)

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.

org.chromium.BiometricsDaemon.EnrollSession

Cancel (Method)

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.

org.chromium.BiometricsDaemon.Record

Remove (Method)

Remove()

Deletes this record object from memory and persistent storage. It will no longer participate in any future Authenticate sessions.

SetLabel (Method)

SetLabel(in STRING label)

Sets the human readable label of this Record object.

Label (Property)

STRING Label

Read-only property that gets the previously set (by either StartEnrollSession or SetLabel) human readable label of this record object.

Example API Usage

The symbol <- means Chrome sends the command to org.chromium.BiometricsDaemon

The symbol -> is either a response or a signal from org.chromium.BiometricsDaemon

  1. 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"
    
  2. User presses finger onto sensor

    -> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Success) false
    
  3. Chrome UI shows encouraging message about that scan to user

  4. User presses finger again but too quickly

    -> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Too Fast) false
    
  5. Chrome UI shows a stern message about how the user's finger is too fast.

  6. [...] Continued until biod determines there is enough data

    -> org.chromium.BiometricsDaemon.BiometricsManager.EnrollScanDone (Success) true
    
  7. Chrome displays successful enrollment message

  8. Logged in user locks screen

    <- Object:/org/chromium/BiometricsDaemon/BiometricsManager0 Method:org.chromium.BiometricsDaemon.BiometricsManager.StartAuthSession
    -> /org/chromium/BiometricsDaemon/BiometricsManager0/AuthSession
    
  9. User does a scan with dirty sensor and lock screen informs the user of this

    -> org.chromium.BiometricsDaemon.BiometricsManager.AuthScanDone (Sensor Dirty) [empty array]
    
  10. User cleans sensor and tries again with success

    -> org.chromium.BiometricsDaemon.BiometricsManager.AuthScanDone (Success) ["unordered_map<string user_id, vector<string record_id>>"]
    
  11. Lock screen lets user in