Add driver_53xc.py — image capture for 27c6:533c (GF5288_GM168SEC) - #75
Add driver_53xc.py — image capture for 27c6:533c (GF5288_GM168SEC)#75nikicat wants to merge 5 commits into
Conversation
Every Device method assumes the sensor sends an ACK frame before the reply:
if isinstance(self.protocol, protocol.USBProtocol):
check_ack(
check_message_protocol(
check_message_pack(self.protocol.read()), COMMAND_ACK),
COMMAND_FIRMWARE_VERSION)
That assumption does not hold for every device. 27c6:533c (GF5288_GM168SEC,
Dell XPS 13 9310) ACKs reset and read_sensor_register but answers
firmware_version and enable_chip with the reply alone. The unconditional read
then consumes that reply, fails to parse it as an ACK, and the command errors
out on a perfectly healthy sensor:
firmware_version() -> ValueError: Invalid message protocol
enable_chip(True) -> USBTimeoutError: [Errno 110] Operation timed out
Add Device._expect_ack(), which reads one frame and puts it back via
Device.read() when it turns out not to be an ACK, so the caller reads it as
the reply. Sensors that do ACK are unaffected -- the ACK is consumed and
verified exactly as before.
This is strictly more permissive, so nothing that worked before changes. It
also collapses 31 five-line blocks into one-liners, for a net -88 lines.
Verified on 27c6:533c, all six commands now succeeding where two used to fail:
nop OK
enable_chip OK (was: USBTimeoutError)
firmware_version OK GF5288_GM168SEC_APP_13016 (was: ValueError)
reset OK (True, 1024)
read_sensor_register OK 0c a1 00 22
read_otp OK 68 e6 86 4a 54 ec 15 04 ...
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d protocol
533c (tested on a Dell XPS 13 9310; also reported for the XPS 13 9300
and XPS 15 9500) has no open driver and its chip model
cannot be read passively -- the USB descriptors say only "Goodix/FingerPrint".
identifier.py asks the sensor directly, trying both message framings.
For 533c the result is:
Firmware version: GF5288_GM168SEC_APP_13016
Chip ID: 0x220ca1
Sensor speaks the wrapped protocol
So it is GF5288 silicon -- same chip as the 53x5 family, and 0x220ca1 >> 8 is
the 0x220C that driver_53x5.py already accepts as sensor type 9 -- but a
different secure element (GM168SEC vs HTSEC) reached over the wrapped framing
rather than the direct one driver_53x5.py is built on. Neither existing driver
matches as-is; a 53xc driver is 53x5's device logic on goodix.py's transport.
One framing delta found already: goodix.Device.firmware_version() expects an
ACK frame before the data reply, and 533c replies with no ACK, so
identifier.read_firmware_version() skips ACKs instead of requiring one.
Read-only by construction: ping, firmware version, sensor reset and register
reads. No firmware erase and no PSK write.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
recon.py reports what a sensor will tell you without writing anything:
firmware version, PSK slot state, chip ID, OTP, and a firmware readback
attempt. The readback matters because mcu_erase_app is irreversible without
an image to flash back and upstream ships none (firmware/ is empty, *.bin is
gitignored) -- so it is worth knowing whether a device will hand its firmware
over before considering any provisioning.
On 27c6:533c it will not:
Firmware: GF5288_GM168SEC_APP_13016
PSK 0xbb020003 / 7 / 1 / 2: not present
Chip ID: 0c a1 00 22 (0x220ca1 -- what driver_53x5 expects)
OTP (32 bytes): 68 e6 86 4a 54 ec 15 04 ...
Firmware dumped: 0 bytes (read_firmware times out in APP mode)
identifier.py carried its own ACK-tolerant firmware_version reader as a
workaround; the previous commit fixes that in goodix.py, so it now calls
device.firmware_version() directly.
Note the PSK slots report nothing at the flag values 51x7 and 55x4 use. A USB
capture of the vendor driver shows it sending a 17-byte preset_psk_read
request with extra fields where goodix.py sends 8, which is the likely reason.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
preset_psk_read takes optional length and offset. Without them goodix.py
sends the 8-byte short form and 533c answers "not present" even though a PSK
is there -- which is what recon.py was doing, and why it reported empty slots.
A USB capture of the vendor driver shows it sending the 16-byte form, and
supplying length/offset makes goodix.py behave identically:
preset_psk_read(0xbb020001, 32, 0) -> 32-byte hash
preset_psk_read(0xbb010002, 102, 0) -> 102-byte wrapped PSK blob
On 533c the hash is:
66687aadf862bd776c8fc18b8e9f8e20089714856ee233b3902a591d0d5f2925
which is sha256 of 32 zero bytes -- the sensor already holds the all-zero PSK
that driver_51x7 and driver_55x4 provision. recon.py now says so explicitly,
because knowing it beforehand means not needing preset_psk_write at all, and
on this device provisioning is irreversible (read_firmware returns nothing in
APP mode, so there is no image to flash back).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
533c is GF5288 silicon (chip 0x220ca1, same as driver_53x5 expects) with a
GM168SEC secure element, speaking the wrapped framing rather than the direct
one. So this is 53x5's device logic on 51x7's transport.
Verified end to end on a Dell XPS 13 9310:
Firmware: GF5288_GM168SEC_APP_13016
PSK: all-zero, as expected
Reset OK, number 1024 Chip ID: 0c a1 00 22
TLS established
FDT template: 9a 9a a6 a6 a2 a2 98 98 97 97 a4 a4 a1 a1 ...
Capturing reference frame (no finger)...
gain 0xc2: 14334 B encrypted -> 14260 B plain
Waiting for finger -- touch the sensor...
gain 0x86: 14334 B encrypted -> 14260 B plain
Wrote fingerprint.pgm
Four things differ from the existing wrapped drivers:
1. No provisioning. 533c already holds the all-zero PSK, and read_firmware
returns nothing in APP mode, so there is no image to flash back if a write
went wrong. The driver checks the PSK hash and refuses to run if it does
not match, rather than calling preset_psk_write.
2. TLS application data is decrypted in process from the session keys,
derived from the randoms observed while relaying the handshake, rather
than read back from openssl's stdout. openssl is still used as the TLS
server. This keeps the image bytes on a single code path that can be
tested offline against a capture, instead of depending on how the
subprocess frames what it echoes.
3. The FDT threshold template is derived, not hardcoded. The baseline reply
is 12-bit samples; halving each and emitting it twice reproduces exactly
what the vendor driver sends.
4. Finger detection polls. The sensor answers fdt_down only when a finger
lands, well past the 5 s default USB read timeout.
Images need a reference frame subtracted -- raw captures are dominated by
fixed-pattern noise. Fitting scale and offset by least squares absorbs the
gain difference too, so one reference frame serves every exposure (the vendor
sweeps gain 0xc2 / 0xad / 0x86).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Nice work -- this is a much cleaner solution than what I independently arrived at for the same device (I'd opened #76 with a driver built around shelling out to Independent cross-validation on different hardware: all-zero PSK already provisioned and 108x88 sensor size both confirmed on my unit too (not an XPS 13 9310) -- for the PSK that's from a live vendor-driver USB capture that never calls PSK-write ACK convention, in case it's ever needed: this chip's DEVICE_CONFIG template locations, as a fallback for machines without a working vendor driver to sniff: the closed |
|
Ran your full stack (#72/#73/#75) against my own 533c unit, not just diffed it -- correction and cross-validation from that: Correction to my last comment: I speculated the six static Further cross-validation, same unit:
(Also, independent of your PR: Net: the protocol/config/geometry side of this is now confirmed across two different physical units, which is about as solid as this gets without a third tester. Nice work. |
|
Follow-up to my earlier comment (correlation r=0.88, no visible ridges): found it. Ran a gain sweep with a finger held down through all captures ( On my unit, So: the protocol/config were never the problem (as established), and this wasn't a Planning to build a native (non-TOD) libfprint driver from this next, using |
Adds a driver for 27c6:533c, verified end to end on a Dell XPS 13 9310.
533c is the same GF5288 silicon as the 53x5 family — chip
0x220ca1, which is exactly whatdriver_53x5.pyaccepts as sensor type 9 — but pairs it with aGM168SECsecure element and speaks the wrapped framing rather than the direct one. So this is 53x5's device logic on 51x7's transport.Run
The resulting PGM shows clear ridge flow. Sensor is 108×88 at 12 bpp, the same geometry as 53x5.
Four differences from the existing wrapped drivers
1. It never provisions, by design. 533c already ships holding the all-zero PSK, and
read_firmwarereturns nothing in APP mode — so there is no image to flash back if a write went wrong, andmcu_erase_appwould be a one-way trip. The driver checks the PSK hash and refuses to run if it does not match, rather than callingpreset_psk_write. That felt safer than the erase-and-reflash loop the other drivers use, given no recovery path exists on this part.2. TLS application data is decrypted in process from the session keys, derived from the client/server randoms observed while relaying the handshake. openssl is still the TLS server. This keeps the image bytes on one code path that can be tested offline against a pcap, rather than depending on how the subprocess frames what it echoes.
3. The FDT threshold template is derived, not hardcoded. The baseline reply is 12-bit samples; halving each and emitting it twice reproduces the vendor driver's bytes exactly. So it self-calibrates rather than carrying magic numbers, unlike the hardcoded templates in
driver_51x7/driver_55x4.4. Finger detection polls, because the sensor answers
fdt_downonly when a finger lands — well past the 5 s default USB read timeout.Image processing
Raw frames are dominated by fixed-pattern noise and do not resemble a fingerprint on their own; a reference frame with no finger has to be subtracted. Fitting scale and offset by least squares absorbs the gain difference as well, so one reference frame serves every exposure — useful because the vendor sweeps gain
0xc2→0xad→0x86.Scope
Image capture only — no enrolment, no matching,
sigfmnot wired up.DEVICE_CONFIGis captured verbatim from the vendor driver on a 9310; other 533c machines may need their own.Tested only on my one device. Happy to adjust anything that does not fit the conventions here.