A libfprint driver for the Goodix 27c6:5F10 fingerprint sensor - the patch-style
reader that ships in HONOR MagicBook laptops and shows up as
USB\VID_27C6&PID_5F10. This repo is a full libfprint tree with one extra driver
on top, sitting on current
libfprint master (1.94.100);
everything outside libfprint/drivers/goodixtls/ is stock.
Status: no longer only my machine. Three other people have run it, on a MagicBook 2023 (GLO-G52), an X14 Plus (FMI-76) and a DRA-XX. More reports are still what I'm after before this goes upstream - see Testing.
The 5F10 is a tiny 56x176 image sensor. It is too small for NBIS minutiae matching
(the same wall the Goodix HTK32 hits), so the driver is not a normal
FpImageDevice. Instead it:
- talks to the chip over the goodixtls TLS-PSK transport (OpenSSL),
- captures raw frames and matches them host-side with sigfm (FAST-9 + BRIEF-256 + RANSAC),
- keeps a small gallery of raw frames in the
FpPrint.
That "FpDevice + host-side sigfm + raw-frame gallery" shape is taken from AndyHazz's goodix53x5 driver - see Credits.
| Sensor | Goodix 27c6:5F10 (ST411SEC), 56x176 |
| Firmware | GF_ST411SEC_APP_12705 |
| Laptops | HONOR MagicBook family |
| Matcher | pure-C sigfm (FAST-9 + BRIEF-256 + RANSAC), no OpenCV |
| Transport | goodixtls, TLS 1.2 PSK (OpenSSL) |
The full detail is below; the shape of it is:
-
Clone this repo - not the original. The original (Sbenazar/goodix-5f10-libfprint) has no Linux provisioning; the fork does:
git clone https://github.com/mounkastel/goodix-5f10-libfprint cd goodix-5f10-libfprint -
Build and install exactly as described in Build and Install. The
-Dlibdir=line in Install is the part people skip; without it fprintd never loads the driver. Stock libfprint 1.94.100 has no driver for the 5F10; build this tree. -
First run only - the driver provisions the sensor's PSK by itself on the first activation, then restart fprintd:
sudo systemctl restart fprintd
No configuration needed. To forbid the driver any write instead:
sudo mkdir -p /etc/systemd/system/fprintd.service.d printf '[Service]\nEnvironment=GOODIX5F10_AUTOPROVISION=0\n' | \ sudo tee /etc/systemd/system/fprintd.service.d/autoprovision.conf sudo systemctl daemon-reload sudo systemctl restart fprintd
-
Enroll and verify - 24 touches, one per
enroll-stage-passedline, the same finger every time, and let it run to the end:fprintd-enroll fprintd-verify
The sections below explain why each piece is there.
Every 5F10 leaves the factory with its own operating point and keeps it in OTP: an analog offset for the read path, and a code that sets the integration time. Three entries of the config table the driver uploads carry it.
Builds before this one shipped that table as it came off my laptop, so every other sensor ran at my operating point - on a DRA-XX, a baseline of 2993 counts where its own OTP asks for 2396. The driver reads the OTP during activation now and rewrites those three.
Prints from an older build should survive. I checked first, since the gallery is raw frames: enrolled at my own DAC, then verified with the config forced to two other people's values. 11 of 14 through at one, 5 of 6 at the other, 11 of 14 for the control
- one finger and that few touches, but nothing I could pick out. New enrollments also carry a stamp of the point they were taken at, so a later surprise turns up in the log instead of as a finger that quietly stops working.
Re-enrolling is worth it anyway, just not for the reason you might think. The old print keeps working; what a fresh one gets you is a gallery recorded at the point your sensor is actually calibrated for, plus the stamp, so if recognition ever does go odd later there's something in the log to look at. How much better it is I honestly don't know - my own measurement couldn't tell the two apart.
GOODIX5F10_NO_OTP_PATCH=1 puts the sensor back on mine if you want to compare.
The 5F10 only speaks TLS, and only with a 32-byte PSK. What ships in every unit
is not a usable TLS key, so the host generates one itself. The TLS-PSK itself is
generated by the host: the host draws 32 random bytes with the system CSPRNG,
wraps them in a small blob and writes them to the MCU with a plain
pre-TLS command (0xE0); it keeps a host copy for itself and reads the chip's
stored hash back with command 0xE4.
So provisioning is a host-side operation, and there is nothing Windows-specific left once you know the wrap. This driver now does the whole thing on Linux:
- Generated with the system CSPRNG.
- Packed with the static key (
goodix5f10_psk.c; Fixed constant of the sensor protocol; identical on every host. Test vectors: see tests/ for the expected output.). - Written with command
0xE0, then read back with0xE4and checked againstSHA256(TLV-1 body). - Persisted to
/var/lib/fprint/goodix-5f10/psk(raw 32 bytes, mode 0600).
The driver provisions automatically during activation whenever there is no key
on disk, or the key on disk does not match the sensor. Set
GOODIX5F10_AUTOPROVISION=0 to opt out and stay read-only: then a missing or
mismatching key fails the open with an error instead of the sensor being
overwritten.
There is also a standalone CLI that does the same over pyusb, with a dry-run default, for recovery and for machines where you cannot rebuild libfprint:
-> tools/goodix-5f10-provision — see its README.
The MCU PSK slot is rewritable (the Windows driver itself re-provisions on a
mismatch), so a write is not a one-shot burn. It is still a write to a device with
no publicly available recovery image. The driver writes on a missing or
mismatching key unless you opt out with GOODIX5F10_AUTOPROVISION=0; the
standalone CLI below, in contrast, never writes without --write.
If you would rather keep using the key Windows already generated, recover it offline and read-only with the companion tool:
It drops 32 raw bytes at /var/lib/fprint/goodix-5f10/psk; the driver loads that
file when it exists. This is now optional, not a requirement.
You need meson, ninja, glib, gusb, udev and OpenSSL headers (on Ubuntu that is
meson ninja-build libglib2.0-dev libgusb-dev libssl-dev systemd-dev). Tested
with meson 1.10.1 and gcc 15.2.0 (Ubuntu 26.04) and MinGW-w64 gcc 16.1.0 (MSYS2);
CI runs the same two commands on Ubuntu on every push.
That list is enough for the driver-only build below. A full build, which is what
you want for Install, also pulls in the other drivers and needs
libpixman-1-dev libcairo2-dev libgudev-1.0-dev on top - without them meson setup stops at "pixman is required for aes3500" or "udev is required for SPI
support" (thanks @dimaCaptain).
Clone this fork, not the original - the original (Sbenazar/goodix-5f10-libfprint) does not have the Linux provisioning work yet:
git clone https://github.com/mounkastel/goodix-5f10-libfprint
cd goodix-5f10-libfprint
meson setup build -Ddrivers=goodixtls5f10 -Ddoc=false -Dgtk-examples=false -Dintrospection=false
ninja -C build./build/libfprint/fprint-list-supported-devices should then list 27c6:5f10.
Building is not enough. fprintd loads libfprint from the system library path, so
the build has to end up there, and meson setup needs to be told where that is -
the default prefix puts it in /usr/local/lib64, which is not in ld.so.conf on
Fedora, and nothing ever picks it up (thanks @nexplorer-3e for that one):
# Fedora and other lib64 distros
meson setup build -Dprefix=/usr -Dlibdir=/usr/lib64 -Ddoc=false -Dgtk-examples=false
# Debian and Ubuntu
meson setup build -Dprefix=/usr -Dlibdir=/usr/lib/x86_64-linux-gnu -Ddoc=false -Dgtk-examples=false
ninja -C build && sudo ninja -C build installIf you're unsure which one you're on, ldconfig -p | grep libfprint-2.so.2 prints
the path the loader actually uses, and that's the directory your build has to land
in.
There's deliberately no -Ddrivers=goodixtls5f10 in that line. It's fine while
you're testing out of the build tree, but a libfprint built with it contains this
driver and nothing else, so installing that leaves your system unable to talk to
any other fingerprint sensor.
One more trap, since I walked into it myself: do not park a backup copy next to
the installed library. libfprint-2.so.2.0.0.bak carries the same SONAME as the
real one, and ldconfig is free to point libfprint-2.so.2 at the backup - after
which you're running the old build and wondering why your changes do nothing.
Keep backups outside the library path.
The sensor will not speak TLS until it has the PSK, and on a freshly wiped Linux install there is usually no key on disk yet. Two ways to get one:
No configuration needed: on the first activation the driver generates 32
random bytes, packs them with the same static key the MCU uses, writes them
to the chip (command 0xE0), reads the stored hash back (0xE4) and requires
it to equal SHA256(TLV-1 body) - only then does it save the raw key to
/var/lib/fprint/goodix-5f10/psk (mode 0600). Every later open just checks
the stored key against the sensor, and a stored key that no longer matches
the chip is re-provisioned (generate, write, verify) the same way.
To forbid all writes instead, opt out:
sudo mkdir -p /etc/systemd/system/fprintd.service.d
printf '[Service]\nEnvironment=GOODIX5F10_AUTOPROVISION=0\n' | \
sudo tee /etc/systemd/system/fprintd.service.d/autoprovision.conf
sudo systemctl daemon-reload
sudo systemctl restart fprintdThen just enroll (below); the first successful activation logs
generated and saved a new PSK to "/var/lib/fprint/goodix-5f10/psk".
(A later re-provision of a mismatching sensor from an existing file logs
writing the stored PSK … / re-provisioned the sensor from the stored PSK instead.)
With GOODIX5F10_AUTOPROVISION=0 nothing is ever written: a missing or
mismatching key fails the open with an error instead of the sensor being
overwritten.
Provisioning is on by default; GOODIX5F10_AUTOPROVISION=0 turns it off.
It exists because the sensor key is a shared slot: the Windows driver also
rewrites it on mismatch, so Linux restores its own key the same way instead
of failing every boot after Windows ran.
Observed on one dual-boot machine: booting Windows to the lock screen, with no sign-in and no fingerprint use, changed the sensor key. The next Linux open rewrote the file key to the sensor and verify passed. Windows Hello kept working after that. This is one test, not a general claim.
tools/goodix-5f10-provision/goodix_5f10_provision.py runs the same bring-up,
generate, write, verify and save over pyusb, and defaults to a read-only dry
run:
# read-only: what the sensor has right now
sudo python3 tools/goodix-5f10-provision/goodix_5f10_provision.py
# generate, write, verify and save a new key
sudo python3 tools/goodix-5f10-provision/goodix_5f10_provision.py --write \
--psk-file /var/lib/fprint/goodix-5f10/pskSee tools/goodix-5f10-provision.
# 1. make sure a PSK the sensor accepts is in place - see "First provision"
sudo systemctl restart fprintd
fprintd-enroll
fprintd-verifyEnrollment is 24 touches - exactly one enroll-stage-passed line per accepted
touch. Use the same finger every time. The driver keeps one best frame per
touch and only checks frame quality (a real ridge patch scores ~260 keypoints
against the 12 required to pass), so almost any contact advances a stage and the
finger is not checked for consistency. A thumb and an index finger both pass;
that is expected. Do not stop early: if you interrupt the enroll, nothing is
stored and fprintd-verify answers NoEnrolledPrints. The verify score gates
are starting values; FAR/FRR are uncharacterised.
On Fedora/RHEL (SELinux) fprintd must be allowed to read the PSK, or activation fails with a permission error. Debian/Ubuntu use AppArmor - fprintd created the file itself, so skip this:
sudo chown root:root /var/lib/fprint/goodix-5f10/psk
sudo chcon -t fprintd_var_lib_t /var/lib/fprint/goodix-5f10/psk
sudo systemctl restart fprintdOne thing to know before you reach for examples/verify instead: it asks which
finger to verify after opening the device, and it reads that answer straight
from stdin inside a main loop callback. While the loop sits there, glib doesn't
refresh the time it hands out to timeouts, so the next command the driver sends
gets a deadline that already expired and fails on the spot with
Command timed out: 0xae. It looks like the sensor went stale during the pause;
it didn't, and the same pause with the loop left running is fine. fprintd never
blocks its loop, so nothing you do through fprintd runs into this.
This is where you come in. I'm gathering reports before opening an upstream MR. If you have a 5F10:
lsusb | grep 27c6:5f10to confirm the sensor.- Provision it - automatic on the first activation, see First provision; recovering the Windows key with goodix-5f10-psk also works.
- Build (above), enroll, verify.
- Paste your
G_MESSAGES_DEBUG=all fprintdlog into libfprint issue #735, or open an issue here. Good or bad, both are useful.
This stands on a stack of prior work:
- the goodixtls TLS transport and protocol base from goodix-fp-linux-dev;
- the pure-C sigfm port from buxel, which in turn comes from the original sigfm authors (Matthieu Charette, Natasha England-Elbro, Timur Mangliev);
- the
FpDevicehost-side-matching architecture from AndyHazz/goodix53x5-libfprint.
LGPL-2.1-or-later, same as libfprint.