libfprint/libfprint/drivers/validity/validity_db.h
Leonardo Francisco 8e0b1efbaf validity: Iteration 6 — Enrollment, Verification, and DB Management
Add core fingerprint operations: enrollment, verification, identification,
print listing, print deletion, and storage clearing.

New files:
- validity_db.h/c: On-chip template database operations — command builders
  for all DB commands (0x45-0x4B, 0x47-0x48, 0x51, 0x5E, 0x60, 0x62, 0x63,
  0x64, 0x68, 0x69, 0x6B), response parsers for DB info/user storage/user/
  record value/record children/new record ID, identity builder (UUID→VCSFW
  binary), finger data builder, and db_write_enable blob accessor.
- validity_enroll.c: 31-state enrollment SSM with interrupt-driven finger
  detection (EP 0x83), capture command orchestration via build_cmd_02(),
  enrollment session management (create/update/commit), DB record creation
  (user + finger), and LED glow feedback.
- validity_verify.c: 17-state verify/identify SSM with match command
  dispatching (cmd 0x5E for verify, cmd 0x60 for identify), 6-state list
  SSM for enumerating enrolled prints via GPtrArray, 8-state delete SSM,
  and clear_storage stub.

Modified files:
- validity.h: Added DB header include, 5 new state enums (CalibState,
  EnrollState, VerifyState, ListState, DeleteState), new struct fields
  for enrollment/verification/list/delete state, function declarations.
- validity.c: Replaced all operation stubs with real implementations,
  added cleanup for new fields in dev_close, wired all FpDevice methods.
- meson.build: Added 3 new source files to driver.
- tests/meson.build: Added test-validity-db executable.
- tests/validity/custom.py: Updated feature assertions (STORAGE,
  STORAGE_LIST, STORAGE_CLEAR now enabled).

Tests: 29 new unit tests in test-validity-db.c covering all command
builders, response parsers, identity/finger data builders, and blob
accessor. All 37 tests pass (0 fail, 2 skip).
2026-04-10 22:18:43 +00:00

285 lines
11 KiB
C

/*
* Database operations for Validity/Synaptics VCSFW sensors
*
* Implements on-chip template database management: listing users,
* storing/deleting fingerprint records, and db_write_enable.
*
* The sensor has a hierarchical record DB stored on flash partition 4:
* Storage → User → Finger → Data
*
* Reference: python-validity db.py, flash.py
*
* Copyright (C) 2024 libfprint contributors
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#pragma once
#include <glib.h>
/* ================================================================
* Database record types (from python-validity observation)
* ================================================================ */
#define VALIDITY_DB_RECORD_TYPE_STORAGE 4
#define VALIDITY_DB_RECORD_TYPE_USER 5
#define VALIDITY_DB_RECORD_TYPE_FINGER 6
#define VALIDITY_DB_RECORD_TYPE_DATA 8
/* Identity type used in record payloads */
#define VALIDITY_IDENTITY_TYPE_SID 3
/* Minimum size for encoded identity (Windows union minimum = 0x4c) */
#define VALIDITY_IDENTITY_MIN_SIZE 0x4C
/* Storage name used by the sensor's DB */
#define VALIDITY_STORAGE_NAME "StgWindsor"
/* Flash partition for calibration data */
#define VALIDITY_FLASH_CALIBRATION_PARTITION 6
/* Clean slate flash header magic */
#define VALIDITY_CLEAN_SLATE_MAGIC 0x5002
/* ================================================================
* DB Info — returned by cmd 0x45
* ================================================================ */
typedef struct
{
guint32 unknown1; /* Always 1 */
guint32 unknown0; /* Always 0 */
guint32 total; /* Partition size */
guint32 used; /* Used (not deleted) */
guint32 free_space; /* Unallocated space */
guint16 records; /* Total number, including deleted */
guint16 n_roots; /* Number of root records */
guint16 *roots; /* Root record IDs (owned, g_free) */
} ValidityDbInfo;
/* ================================================================
* User Storage — returned by cmd 0x4B
* Represents a named storage container that holds users.
* ================================================================ */
typedef struct
{
guint16 dbid;
guint16 user_count;
gchar *name; /* owned, g_free */
/* Per-user entries: array of {dbid, value_size} pairs */
guint16 *user_dbids;
guint16 *user_val_sizes;
} ValidityUserStorage;
/* ================================================================
* Finger record entry — part of a User record
* ================================================================ */
typedef struct
{
guint16 dbid;
guint16 subtype; /* WINBIO finger constant (1-10) */
guint16 storage;
guint16 value_size;
} ValidityFingerEntry;
/* ================================================================
* User — returned by cmd 0x4A
* ================================================================ */
typedef struct
{
guint16 dbid;
guint16 finger_count;
guint8 *identity; /* Raw identity bytes, owned */
gsize identity_len;
ValidityFingerEntry *fingers; /* owned array of finger_count entries */
} ValidityUser;
/* ================================================================
* DB Record — returned by cmd 0x49 (get_record_value)
* ================================================================ */
typedef struct
{
guint16 dbid;
guint16 type;
guint16 storage;
guint8 *value; /* owned, g_free */
gsize value_len;
} ValidityDbRecord;
/* ================================================================
* Record child entry — from cmd 0x46 (get_record_children)
* ================================================================ */
typedef struct
{
guint16 dbid;
guint16 type;
} ValidityRecordChild;
typedef struct
{
guint16 dbid;
guint16 type;
guint16 storage;
guint16 child_count;
ValidityRecordChild *children; /* owned array */
} ValidityRecordChildren;
/* ================================================================
* Command builders — produce binary TLS command payloads
*
* All returned buffers are g_malloc'd and must be g_free'd by caller.
* ================================================================ */
/* cmd 0x45: DB info */
guint8 *validity_db_build_cmd_info (gsize *out_len);
/* cmd 0x4B: Get user storage by name */
guint8 *validity_db_build_cmd_get_user_storage (const gchar *name,
gsize *out_len);
/* cmd 0x4A: Get user by dbid */
guint8 *validity_db_build_cmd_get_user (guint16 dbid,
gsize *out_len);
/* cmd 0x4A: Lookup user by identity within a storage */
guint8 *validity_db_build_cmd_lookup_user (guint16 storage_dbid,
const guint8 *identity,
gsize identity_len,
gsize *out_len);
/* cmd 0x49: Get record value */
guint8 *validity_db_build_cmd_get_record_value (guint16 dbid,
gsize *out_len);
/* cmd 0x46: Get record children */
guint8 *validity_db_build_cmd_get_record_children (guint16 dbid,
gsize *out_len);
/* cmd 0x47: New record */
guint8 *validity_db_build_cmd_new_record (guint16 parent,
guint16 type,
guint16 storage,
const guint8 *data,
gsize data_len,
gsize *out_len);
/* cmd 0x48: Delete record */
guint8 *validity_db_build_cmd_del_record (guint16 dbid,
gsize *out_len);
/* cmd 0x1a: Call cleanups (commit pending writes) */
guint8 *validity_db_build_cmd_call_cleanups (gsize *out_len);
/* ================================================================
* Response parsers — parse binary TLS response payloads
*
* All parse functions take data AFTER the 2-byte status has been stripped.
* Return TRUE on success, FALSE on parse error.
* ================================================================ */
gboolean validity_db_parse_info (const guint8 *data,
gsize data_len,
ValidityDbInfo *out);
gboolean validity_db_parse_user_storage (const guint8 *data,
gsize data_len,
ValidityUserStorage *out);
gboolean validity_db_parse_user (const guint8 *data,
gsize data_len,
ValidityUser *out);
gboolean validity_db_parse_record_value (const guint8 *data,
gsize data_len,
ValidityDbRecord *out);
gboolean validity_db_parse_record_children (const guint8 *data,
gsize data_len,
ValidityRecordChildren *out);
/* cmd 0x47 response: parse new record ID */
gboolean validity_db_parse_new_record_id (const guint8 *data,
gsize data_len,
guint16 *out_record_id);
/* ================================================================
* Identity helpers
* ================================================================ */
/* Build a UUID-based identity suitable for the sensor DB.
* Returns a buffer of at least VALIDITY_IDENTITY_MIN_SIZE bytes. */
guint8 *validity_db_build_identity (const gchar *uuid_str,
gsize *out_len);
/* Build finger data payload for new_finger (format from make_finger_data) */
guint8 *validity_db_build_finger_data (guint16 subtype,
const guint8 *template_data,
gsize template_len,
const guint8 *tid,
gsize tid_len,
gsize *out_len);
/* ================================================================
* Structure cleanup helpers
* ================================================================ */
void validity_db_info_clear (ValidityDbInfo *info);
void validity_user_storage_clear (ValidityUserStorage *storage);
void validity_user_clear (ValidityUser *user);
void validity_db_record_clear (ValidityDbRecord *record);
void validity_record_children_clear (ValidityRecordChildren *children);
/* ================================================================
* Enrollment commands
* ================================================================ */
/* cmd 0x69: Create enrollment (start) / End enrollment */
guint8 *validity_db_build_cmd_create_enrollment (gboolean start,
gsize *out_len);
/* cmd 0x68: Enrollment update start */
guint8 *validity_db_build_cmd_enrollment_update_start (guint32 key,
gsize *out_len);
/* cmd 0x6B: Enrollment update (with template data) */
guint8 *validity_db_build_cmd_enrollment_update (const guint8 *prev_data,
gsize prev_len,
gsize *out_len);
/* cmd 0x51: Get program status */
guint8 *validity_db_build_cmd_get_prg_status (gboolean extended,
gsize *out_len);
/* cmd 0x04: Capture stop */
guint8 *validity_db_build_cmd_capture_stop (gsize *out_len);
/* ================================================================
* Match commands
* ================================================================ */
/* cmd 0x5E: Match finger */
guint8 *validity_db_build_cmd_match_finger (gsize *out_len);
/* cmd 0x60: Get match result */
guint8 *validity_db_build_cmd_get_match_result (gsize *out_len);
/* cmd 0x62: Match cleanup */
guint8 *validity_db_build_cmd_match_cleanup (gsize *out_len);
/* ================================================================
* db_write_enable blob access
* ================================================================ */
const guint8 *validity_db_get_write_enable_blob (gsize *out_len);