validity: fix code style (uncrustify) and test assertions

Apply uncrustify formatting to all validity driver and test files
to pass the CI test_indent check.

Fix two pre-existing test failures:
- test-validity-capture: LED command blobs are 125 bytes, not 128
- test-validity-enroll: add 2-byte length prefix to test data to
  match parser's expected format, fix empty-data assertion (parser
  returns FALSE for data_len < 2)

All 41 tests pass, 0 failures.
This commit is contained in:
Leonardo Francisco 2026-04-07 22:44:26 -04:00 committed by lewohart
parent a486b58c5a
commit 4bf976c7b5
29 changed files with 943 additions and 849 deletions

View file

@ -289,8 +289,8 @@ fwext_upload_ssm_done (FpiSsm *ssm,
* that tells fprintd to retry. */
fp_info ("Firmware extension uploaded successfully — device rebooting");
fpi_ssm_mark_failed (self->open_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_REMOVED,
"Device rebooting after firmware upload"));
fpi_device_error_new_msg (FP_DEVICE_ERROR_REMOVED,
"Device rebooting after firmware upload"));
}
/* Callback for pairing child SSM */
@ -332,8 +332,8 @@ pair_ssm_done (FpiSsm *ssm,
fp_info ("Pairing complete — device rebooting, signalling removal");
validity_pair_state_free (&self->pair_state);
fpi_ssm_mark_failed (self->open_ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_REMOVED,
"Device rebooting after pairing"));
fpi_device_error_new_msg (FP_DEVICE_ERROR_REMOVED,
"Device rebooting after pairing"));
return;
}
@ -626,8 +626,8 @@ open_run_state (FpiSsm *ssm,
* TLS works independently of fwext (partition 2). */
self->open_ssm = ssm;
FpiSsm *flash_ssm = fpi_ssm_new (dev,
validity_tls_flash_read_run_state,
TLS_FLASH_READ_NUM_STATES);
validity_tls_flash_read_run_state,
TLS_FLASH_READ_NUM_STATES);
fpi_ssm_start (flash_ssm, flash_read_ssm_done);
}
break;
@ -692,8 +692,8 @@ open_run_state (FpiSsm *ssm,
self->open_ssm = ssm;
FpiSsm *tls_ssm = fpi_ssm_new (dev,
validity_tls_handshake_run_state,
TLS_HS_NUM_STATES);
validity_tls_handshake_run_state,
TLS_HS_NUM_STATES);
fpi_ssm_start (tls_ssm, tls_handshake_ssm_done);
}
break;
@ -766,13 +766,17 @@ open_run_state (FpiSsm *ssm,
self->sensor.device_info->type);
if (self->sensor.type_info)
fp_info ("Sensor type: 0x%04x, %u bytes/line, %ux repeat",
self->sensor.type_info->sensor_type,
self->sensor.type_info->bytes_per_line,
self->sensor.type_info->repeat_multiplier);
{
fp_info ("Sensor type: 0x%04x, %u bytes/line, %ux repeat",
self->sensor.type_info->sensor_type,
self->sensor.type_info->bytes_per_line,
self->sensor.type_info->repeat_multiplier);
}
else
fp_warn ("Unknown sensor type 0x%04x",
self->sensor.device_info->type);
{
fp_warn ("Unknown sensor type 0x%04x",
self->sensor.device_info->type);
}
}
else
{
@ -939,9 +943,9 @@ open_run_state (FpiSsm *ssm,
/* Read calibration data from EP 0x82.
* PY: usb.read_82() reads all bulk data from the sensor. */
{
gsize expected_size = (gsize)(self->capture.calibration_frames *
self->capture.lines_per_frame + 1) *
self->capture.bytes_per_line;
gsize expected_size = (gsize) (self->capture.calibration_frames *
self->capture.lines_per_frame + 1) *
self->capture.bytes_per_line;
FpiUsbTransfer *xfer = fpi_usb_transfer_new (dev);
fp_dbg ("Reading calibration data: %zu bytes from EP 0x82",
@ -1015,7 +1019,9 @@ open_run_state (FpiSsm *ssm,
self->calib_iteration++;
if (self->calib_iteration < self->capture.calibration_iterations)
fpi_ssm_jump_to_state (ssm, OPEN_CALIBRATE_SEND);
{
fpi_ssm_jump_to_state (ssm, OPEN_CALIBRATE_SEND);
}
else
{
fp_info ("Sensor calibration complete");

View file

@ -29,23 +29,23 @@
#include "validity_tls.h"
/* USB Endpoint addresses */
#define VALIDITY_EP_CMD_OUT 0x01
#define VALIDITY_EP_CMD_IN 0x81
#define VALIDITY_EP_DATA_IN 0x82
#define VALIDITY_EP_INT_IN 0x83
#define VALIDITY_EP_CMD_OUT 0x01
#define VALIDITY_EP_CMD_IN 0x81
#define VALIDITY_EP_DATA_IN 0x82
#define VALIDITY_EP_INT_IN 0x83
/* USB transfer parameters */
#define VALIDITY_USB_TIMEOUT 15000
#define VALIDITY_USB_INT_TIMEOUT 100
#define VALIDITY_MAX_TRANSFER_LEN (100 * 1024)
#define VALIDITY_USB_TIMEOUT 15000
#define VALIDITY_USB_INT_TIMEOUT 100
#define VALIDITY_MAX_TRANSFER_LEN (100 * 1024)
#define VALIDITY_USB_INT_DATA_SIZE 1024
#define VALIDITY_USB_SEND_HEADER_LEN 1
/* Number of enroll stages */
#define VALIDITY_ENROLL_STAGES 8
#define VALIDITY_ENROLL_STAGES 8
/* Interrupt response bits */
#define VALIDITY_INT_FINGER_DOWN 0x02
#define VALIDITY_INT_FINGER_DOWN 0x02
#define VALIDITY_INT_SCAN_COMPLETE 0x04
typedef enum {
@ -243,14 +243,14 @@ G_DECLARE_FINAL_TYPE (FpiDeviceValidity, fpi_device_validity,
struct _FpiDeviceValidity
{
FpDevice parent;
FpDevice parent;
ValidityDeviceType dev_type;
ValidityDeviceType dev_type;
ValidityVersionInfo version_info;
GCancellable *interrupt_cancellable;
GCancellable *interrupt_cancellable;
/* TLS session state */
ValidityTlsState tls;
ValidityTlsState tls;
/* Sensor identification and HAL state (post-TLS) */
ValiditySensorState sensor;
@ -259,50 +259,50 @@ struct _FpiDeviceValidity
ValidityCaptureState capture;
/* Firmware extension status */
gboolean fwext_loaded;
gboolean fwext_loaded;
/* Pairing state (for uninitialized devices) */
ValidityPairState pair_state;
ValidityPairState pair_state;
/* Calibration state */
gboolean calibrated;
guint calib_iteration;
gboolean calibrated;
guint calib_iteration;
/* Enrollment state */
guint32 enroll_key;
guint8 *enroll_template;
gsize enroll_template_len;
guint enroll_stage;
guint16 enroll_user_dbid;
guint16 enroll_storage_dbid;
guint scan_incomplete_count;
guint32 enroll_key;
guint8 *enroll_template;
gsize enroll_template_len;
guint enroll_stage;
guint16 enroll_user_dbid;
guint16 enroll_storage_dbid;
guint scan_incomplete_count;
/* Verify/identify mode flag: TRUE = identify, FALSE = verify */
gboolean identify_mode;
gboolean identify_mode;
/* List prints state */
ValidityUserStorage list_storage;
guint list_user_idx;
guint list_user_idx;
/* Delete state */
guint16 delete_storage_dbid;
guint16 delete_finger_subtype;
guint16 delete_finger_dbid;
guint16 delete_storage_dbid;
guint16 delete_finger_subtype;
guint16 delete_finger_dbid;
/* Command SSM: manages the send-cmd/recv-response cycle */
FpiSsm *cmd_ssm;
FpiSsm *cmd_ssm;
/* Parent SSM: back-pointer for non-subsm child SSMs */
FpiSsm *open_ssm;
FpiSsm *open_ssm;
/* Pending response data stashed for higher-level SSM consumption */
guint16 cmd_response_status;
guint8 *cmd_response_data;
gsize cmd_response_len;
guint16 cmd_response_status;
guint8 *cmd_response_data;
gsize cmd_response_len;
/* Bulk data buffer (EP 0x82 reads during capture/calibration) */
guint8 *bulk_data;
gsize bulk_data_len;
guint8 *bulk_data;
gsize bulk_data_len;
};
/* Enrollment SSM (validity_enroll.c) */
@ -322,9 +322,9 @@ typedef struct
} EnrollmentUpdateResult;
void enrollment_update_result_clear (EnrollmentUpdateResult *r);
gboolean parse_enrollment_update_response (const guint8 *data,
gsize data_len,
EnrollmentUpdateResult *result);
gboolean parse_enrollment_update_response (const guint8 *data,
gsize data_len,
EnrollmentUpdateResult *result);
/* Verify/Identify SSMs (validity_verify.c) */
void validity_verify (FpDevice *device);

View file

@ -41,7 +41,7 @@ validity_capture_split_chunks (const guint8 *data,
gsize *n_chunks)
{
GArray *arr;
gsize offset = 0;
gsize offset = 0;
g_return_val_if_fail (data != NULL || data_len == 0, NULL);
g_return_val_if_fail (n_chunks != NULL, NULL);
@ -81,9 +81,9 @@ validity_capture_merge_chunks (const ValidityCaptureChunk *chunks,
gsize n_chunks,
gsize *out_len)
{
gsize total = 0;
gsize total = 0;
guint8 *buf;
gsize offset = 0;
gsize offset = 0;
g_return_val_if_fail (out_len != NULL, NULL);
@ -192,7 +192,7 @@ validity_capture_decode_insn (const guint8 *data,
return FALSE;
*opcode = TST_OP_ENABLE_SO;
*insn_len = 2;
operands[0] = ((guint32)(b0 & 1) << 8) | data[1];
operands[0] = ((guint32) (b0 & 1) << 8) | data[1];
*n_operands = 1;
return TRUE;
}
@ -204,7 +204,7 @@ validity_capture_decode_insn (const guint8 *data,
return FALSE;
*opcode = TST_OP_DISABLE_SO;
*insn_len = 2;
operands[0] = ((guint32)(b0 & 1) << 8) | data[1];
operands[0] = ((guint32) (b0 & 1) << 8) | data[1];
*n_operands = 1;
return TRUE;
}
@ -250,7 +250,7 @@ validity_capture_decode_insn (const guint8 *data,
return FALSE;
*opcode = TST_OP_REG_WRITE;
*insn_len = 3;
operands[0] = (guint32)(b0 & 0x3f) * 4 + 0x80002000; /* register address */
operands[0] = (guint32) (b0 & 0x3f) * 4 + 0x80002000; /* register address */
operands[1] = (guint32) data[1] | ((guint32) data[2] << 8); /* value */
*n_operands = 2;
return TRUE;
@ -294,7 +294,7 @@ validity_capture_find_nth_insn (const guint8 *data,
while (pc < data_len)
{
guint8 opcode, len, n_ops;
guint8 opcode, len, n_ops;
guint32 operands[3];
if (!validity_capture_decode_insn (data + pc, data_len - pc,
@ -324,7 +324,7 @@ validity_capture_find_nth_regwrite (const guint8 *data,
while (pc < data_len)
{
guint8 opcode, len, n_ops;
guint8 opcode, len, n_ops;
guint32 operands[3];
if (!validity_capture_decode_insn (data + pc, data_len - pc,
@ -402,7 +402,7 @@ validity_capture_patch_timeslot_again (guint8 *data,
guint16 key_calibration_line)
{
gssize call_target = -1;
gsize pc = 0;
gsize pc = 0;
gssize match = -1;
g_return_val_if_fail (data != NULL, FALSE);
@ -411,7 +411,7 @@ validity_capture_patch_timeslot_again (guint8 *data,
/* First pass: find the last Call instruction's destination address */
while (pc < data_len)
{
guint8 opcode, len, n_ops;
guint8 opcode, len, n_ops;
guint32 operands[3];
if (!validity_capture_decode_insn (data + pc, data_len - pc,
@ -438,7 +438,7 @@ validity_capture_patch_timeslot_again (guint8 *data,
pc = (gsize) call_target;
while (pc < data_len)
{
guint8 opcode, len, n_ops;
guint8 opcode, len, n_ops;
guint32 operands[3];
if (!validity_capture_decode_insn (data + pc, data_len - pc,
@ -477,9 +477,11 @@ validity_capture_patch_timeslot_again (guint8 *data,
static guint8
clip_signed (gint x)
{
if (x < -128) x = -128;
if (x > 127) x = 127;
return (guint8)(x & 0xff);
if (x < -128)
x = -128;
if (x > 127)
x = 127;
return (guint8) (x & 0xff);
}
/* Scale a byte value for calibration processing */
@ -487,6 +489,7 @@ static guint8
scale_byte (guint8 x)
{
gint val = (gint) x - 0x80;
val = val * 10 / 0x22;
return clip_signed (val);
}
@ -497,6 +500,7 @@ add_signed_bytes (guint8 l, guint8 r)
{
gint8 sl = (gint8) l;
gint8 sr = (gint8) r;
return clip_signed ((gint) sl + (gint) sr);
}
@ -513,11 +517,11 @@ validity_capture_bitpack (const guint8 *values,
guint8 *out_v1,
gsize *out_len)
{
guint8 min_val = 0xff, max_val = 0;
guint8 useful_bits;
guint max_delta;
gsize total_bits;
gsize total_bytes;
guint8 min_val = 0xff, max_val = 0;
guint8 useful_bits;
guint max_delta;
gsize total_bits;
gsize total_bytes;
guint8 *packed;
g_return_val_if_fail (values != NULL && values_len > 0, NULL);
@ -526,8 +530,10 @@ validity_capture_bitpack (const guint8 *values,
/* Find min and max */
for (gsize i = 0; i < values_len; i++)
{
if (values[i] < min_val) min_val = values[i];
if (values[i] > max_val) max_val = values[i];
if (values[i] < min_val)
min_val = values[i];
if (values[i] > max_val)
max_val = values[i];
}
max_delta = max_val - min_val;
@ -610,10 +616,8 @@ get_key_line (const guint8 *calib_data,
memcpy (key_line, calib_data + key_offset, line_width);
/* Replace value 5 with 4 (python: [i-1 if i == 5 else i for i in key_line]) */
for (guint16 i = 0; i < line_width; i++)
{
if (key_line[i] == 5)
key_line[i] = 4;
}
if (key_line[i] == 5)
key_line[i] = 4;
}
}
@ -633,13 +637,13 @@ get_key_line (const guint8 *calib_data,
/* Internal line entry for building Line Update chunks */
typedef struct
{
guint32 mask;
guint32 flags;
guint8 *data;
gsize data_len;
guint8 v0; /* bitpack: useful bits */
guint8 v1; /* bitpack: minimum */
guint16 v2; /* unused in type 1, always 0 */
guint32 mask;
guint32 flags;
guint8 *data;
gsize data_len;
guint8 v0; /* bitpack: useful bits */
guint8 v1; /* bitpack: minimum */
guint16 v2; /* unused in type 1, always 0 */
} LineEntry;
/*
@ -654,22 +658,22 @@ typedef struct
* n_chunks is updated with the new count.
*/
static ValidityCaptureChunk *
build_line_update_type1 (const ValidityCaptureState *capture,
const ValiditySensorTypeInfo *type_info,
ValidityCaptureMode mode,
ValidityCaptureChunk *in_chunks,
gsize in_n_chunks,
gsize *out_n_chunks)
build_line_update_type1 (const ValidityCaptureState *capture,
const ValiditySensorTypeInfo *type_info,
ValidityCaptureMode mode,
ValidityCaptureChunk *in_chunks,
gsize in_n_chunks,
gsize *out_n_chunks)
{
GArray *chunks_arr;
GArray *lines_arr;
gsize cnt = 2; /* line counter starts at 2 per python-validity */
gsize cnt = 2; /* line counter starts at 2 per python-validity */
/* Save the patched TST (before key_line replacement) for instruction
* searches later. PY searches the original patched tst variable, not
* the chunk data that has the key_line prepended. */
g_autofree guint8 *patched_tst = NULL;
gsize patched_tst_len = 0;
gsize patched_tst_len = 0;
/* Copy input chunks, patching timeslot table in-place */
chunks_arr = g_array_new (FALSE, TRUE, sizeof (ValidityCaptureChunk));
@ -685,12 +689,14 @@ build_line_update_type1 (const ValidityCaptureState *capture,
if (c.type == CAPT_CHUNK_TIMESLOT_2D && c.data && c.size > 0)
{
validity_capture_patch_timeslot_table (c.data, c.size, TRUE,
type_info->repeat_multiplier);
type_info->repeat_multiplier);
if (mode != VALIDITY_CAPTURE_CALIBRATE)
validity_capture_patch_timeslot_again (c.data, c.size,
capture->factory_calibration_values,
capture->factory_calibration_values_len,
capture->key_calibration_line);
{
validity_capture_patch_timeslot_again (c.data, c.size,
capture->factory_calibration_values,
capture->factory_calibration_values_len,
capture->key_calibration_line);
}
/* Save the patched TST before key_line replacement.
* Instruction searches must use this, not the key_line-modified data. */
@ -846,88 +852,90 @@ build_line_update_type1 (const ValidityCaptureState *capture,
lines_arr = g_array_new (FALSE, TRUE, sizeof (LineEntry));
/* We need the patched timeslot table (before key_line replacement)
* for instruction searches see PY's line_update_type_1 which uses
* the 'tst' variable, not 'c[1]' (which has key_line prepended). */
* for instruction searches see PY's line_update_type_1 which uses
* the 'tst' variable, not 'c[1]' (which has key_line prepended). */
if (patched_tst && patched_tst_len > 0)
{
const guint8 *tst_data = patched_tst;
gsize tst_len = patched_tst_len;
/* Line 0: calibration blob at Enable Rx position */
{
gssize pc = validity_capture_find_nth_insn (tst_data, tst_len,
TST_OP_ENABLE_RX, 2);
if (pc >= 0 && type_info->calibration_blob)
{
LineEntry le = { 0 };
le.mask = 0xff;
le.flags = ((guint32)(pc + 1)) | ((guint32) cnt << 0x14) | 0x7000000;
le.data = g_memdup2 (type_info->calibration_blob,
type_info->calibration_blob_len);
le.data_len = type_info->calibration_blob_len;
le.v0 = 0x0f;
g_array_append_val (lines_arr, le);
cnt++;
}
}
/* Line 1: factory calibration values at Register Write position */
{
gssize pc = validity_capture_find_nth_regwrite (tst_data, tst_len,
0x8000203C, 1);
if (pc >= 0 && capture->factory_calibration_values)
{
LineEntry le = { 0 };
le.mask = 0xff;
le.flags = ((guint32)(pc + 1)) | ((guint32) cnt << 0x14) | 0x7000000;
/* Bitpack the factory calibration values */
le.data = validity_capture_bitpack (
capture->factory_calibration_values,
capture->factory_calibration_values_len,
&le.v0, &le.v1, &le.data_len);
le.v0 = (le.v0 - 1) | 8;
cnt++;
g_array_append_val (lines_arr, le);
}
}
/* Calibration data lines (if we have calib_data) */
if (capture->calib_data && capture->calib_data_len > 0)
gsize tst_len = patched_tst_len;
/* Line 0: calibration blob at Enable Rx position */
{
gssize pc = validity_capture_find_nth_insn (tst_data, tst_len,
TST_OP_ENABLE_RX, 2);
if (pc >= 0 && type_info->calibration_blob)
{
gsize bytes_per_cal_line = capture->calib_data_len /
type_info->lines_per_calibration_data;
for (guint i = 0; i < 112; i += 4)
{
LineEntry le = { 0 };
le.mask = 0xffffffff;
le.flags = i | (0x85u << 24);
/* Collect data from each calibration line at offset i */
gsize row_data_len = 0;
GByteArray *row = g_byte_array_new ();
for (guint j = 0; j < 112; j++)
{
gsize p = 8 + (gsize) j * bytes_per_cal_line + i;
if (p + 4 <= capture->calib_data_len)
g_byte_array_append (row, capture->calib_data + p, 4);
else
{
guint8 zeros[4] = { 0 };
g_byte_array_append (row, zeros, 4);
}
}
le.data_len = row->len;
le.data = g_byte_array_free (row, FALSE);
row_data_len = le.data_len;
(void) row_data_len;
g_array_append_val (lines_arr, le);
}
LineEntry le = { 0 };
le.mask = 0xff;
le.flags = ((guint32) (pc + 1)) | ((guint32) cnt << 0x14) | 0x7000000;
le.data = g_memdup2 (type_info->calibration_blob,
type_info->calibration_blob_len);
le.data_len = type_info->calibration_blob_len;
le.v0 = 0x0f;
g_array_append_val (lines_arr, le);
cnt++;
}
}
/* Line 1: factory calibration values at Register Write position */
{
gssize pc = validity_capture_find_nth_regwrite (tst_data, tst_len,
0x8000203C, 1);
if (pc >= 0 && capture->factory_calibration_values)
{
LineEntry le = { 0 };
le.mask = 0xff;
le.flags = ((guint32) (pc + 1)) | ((guint32) cnt << 0x14) | 0x7000000;
/* Bitpack the factory calibration values */
le.data = validity_capture_bitpack (
capture->factory_calibration_values,
capture->factory_calibration_values_len,
&le.v0, &le.v1, &le.data_len);
le.v0 = (le.v0 - 1) | 8;
cnt++;
g_array_append_val (lines_arr, le);
}
}
/* Calibration data lines (if we have calib_data) */
if (capture->calib_data && capture->calib_data_len > 0)
{
gsize bytes_per_cal_line = capture->calib_data_len /
type_info->lines_per_calibration_data;
for (guint i = 0; i < 112; i += 4)
{
LineEntry le = { 0 };
le.mask = 0xffffffff;
le.flags = i | (0x85u << 24);
/* Collect data from each calibration line at offset i */
gsize row_data_len = 0;
GByteArray *row = g_byte_array_new ();
for (guint j = 0; j < 112; j++)
{
gsize p = 8 + (gsize) j * bytes_per_cal_line + i;
if (p + 4 <= capture->calib_data_len)
{
g_byte_array_append (row, capture->calib_data + p, 4);
}
else
{
guint8 zeros[4] = { 0 };
g_byte_array_append (row, zeros, 4);
}
}
le.data_len = row->len;
le.data = g_byte_array_free (row, FALSE);
row_data_len = le.data_len;
(void) row_data_len;
g_array_append_val (lines_arr, le);
}
}
}
/* Align all line data to 4-byte boundary */
@ -1028,19 +1036,19 @@ build_line_update_type1 (const ValidityCaptureState *capture,
* ================================================================ */
guint8 *
validity_capture_build_cmd_02 (const ValidityCaptureState *capture,
validity_capture_build_cmd_02 (const ValidityCaptureState *capture,
const ValiditySensorTypeInfo *type_info,
ValidityCaptureMode mode,
gsize *out_len)
{
ValidityCaptureChunk *chunks = NULL;
ValidityCaptureChunk *patched = NULL;
gsize n_chunks = 0;
gsize n_patched = 0;
guint8 *merged = NULL;
gsize merged_len = 0;
guint8 *cmd = NULL;
guint16 req_lines;
gsize n_chunks = 0;
gsize n_patched = 0;
guint8 *merged = NULL;
gsize merged_len = 0;
guint8 *cmd = NULL;
guint16 req_lines;
g_return_val_if_fail (capture != NULL, NULL);
g_return_val_if_fail (type_info != NULL, NULL);
@ -1060,7 +1068,7 @@ validity_capture_build_cmd_02 (const ValidityCaptureState *capture,
if (capture->is_type1_device)
{
patched = build_line_update_type1 (capture, type_info, mode,
chunks, n_chunks, &n_patched);
chunks, n_chunks, &n_patched);
}
else
{
@ -1089,7 +1097,7 @@ validity_capture_build_cmd_02 (const ValidityCaptureState *capture,
/* Calculate requested lines */
if (mode == VALIDITY_CAPTURE_CALIBRATE)
req_lines = (guint16)(capture->calibration_frames * capture->lines_per_frame + 1);
req_lines = (guint16) (capture->calibration_frames * capture->lines_per_frame + 1);
else
req_lines = 0;
@ -1123,15 +1131,15 @@ validity_capture_build_cmd_02 (const ValidityCaptureState *capture,
* ================================================================ */
gboolean
validity_capture_parse_factory_bits (const guint8 *data,
gsize data_len,
guint8 **cal_values,
gsize *cal_values_len,
guint8 **cal_data,
gsize *cal_data_len)
validity_capture_parse_factory_bits (const guint8 *data,
gsize data_len,
guint8 **cal_values,
gsize *cal_values_len,
guint8 **cal_data,
gsize *cal_data_len)
{
guint32 wtf, entries;
gsize offset;
gsize offset;
gboolean found_subtag3 = FALSE;
g_return_val_if_fail (data != NULL, FALSE);
@ -1214,12 +1222,12 @@ validity_capture_average_frames (const guint8 *raw_data,
guint8 calibration_frames,
gsize *out_len)
{
gsize frame_size;
gsize frame_size;
guint16 interleave_lines;
guint8 input_frames;
gsize base_address = 0;
guint8 input_frames;
gsize base_address = 0;
guint8 *result;
gsize result_len;
gsize result_len;
g_return_val_if_fail (raw_data != NULL, NULL);
g_return_val_if_fail (out_len != NULL, NULL);
@ -1272,7 +1280,7 @@ validity_capture_average_frames (const guint8 *raw_data,
sum += frame[idx];
}
result[(gsize) line * bytes_per_line + col] =
(guint8)(sum / interleave_lines);
(guint8) (sum / interleave_lines);
}
}
@ -1297,7 +1305,7 @@ validity_capture_average_frames (const guint8 *raw_data,
if (idx < raw_len)
sum += raw_data[idx];
}
result[i] = (guint8)(sum / input_frames);
result[i] = (guint8) (sum / input_frames);
}
*out_len = result_len;
@ -1325,11 +1333,11 @@ validity_capture_average_frames (const guint8 *raw_data,
* ================================================================ */
void
validity_capture_process_calibration (guint8 **calib_data,
gsize *calib_data_len,
const guint8 *averaged_frame,
gsize frame_len,
guint16 bytes_per_line)
validity_capture_process_calibration (guint8 **calib_data,
gsize *calib_data_len,
const guint8 *averaged_frame,
gsize frame_len,
guint16 bytes_per_line)
{
guint8 *frame_scaled;
@ -1363,7 +1371,7 @@ validity_capture_process_calibration (guint8 **calib_data,
/* First 8 bytes: keep as-is from previous */
for (gsize col = 8; col < bytes_per_line && off + col < len; col++)
(*calib_data)[off + col] = add_signed_bytes ((*calib_data)[off + col],
frame_scaled[off + col]);
frame_scaled[off + col]);
}
}
else
@ -1469,10 +1477,8 @@ validity_capture_verify_clean_slate (const guint8 *data,
/* Check zeroes block */
for (int i = 0; i < 32; i++)
{
if (zeroes[i] != 0)
return FALSE;
}
if (zeroes[i] != 0)
return FALSE;
/* Verify hash */
if (68 + inner_len > data_len)
@ -1728,10 +1734,10 @@ static const guint16 line_update_type1_devices[] = {
};
const guint8 *
validity_capture_prog_lookup (guint8 rom_major,
guint8 rom_minor,
guint16 dev_type,
gsize *out_len)
validity_capture_prog_lookup (guint8 rom_major,
guint8 rom_minor,
guint16 dev_type,
gsize *out_len)
{
g_return_val_if_fail (out_len != NULL, NULL);
@ -1791,7 +1797,7 @@ validity_capture_state_setup (ValidityCaptureState *state,
gsize factory_bits_len)
{
const guint8 *prog;
gsize prog_len;
gsize prog_len;
g_return_val_if_fail (state != NULL, FALSE);
g_return_val_if_fail (type_info != NULL, FALSE);
@ -1830,7 +1836,7 @@ validity_capture_state_setup (ValidityCaptureState *state,
if (chunks[i].type == CAPT_CHUNK_2D_PARAMS && chunks[i].size >= 4)
{
guint32 lines_2d = FP_READ_UINT32_LE (chunks[i].data);
state->lines_per_frame = (guint16)(lines_2d * type_info->repeat_multiplier);
state->lines_per_frame = (guint16) (lines_2d * type_info->repeat_multiplier);
break;
}
}

View file

@ -46,9 +46,9 @@ typedef enum {
* ================================================================ */
typedef struct
{
guint16 type;
guint16 size;
guint8 *data; /* owned; g_free() when done */
guint16 type;
guint16 size;
guint8 *data; /* owned; g_free() when done */
} ValidityCaptureChunk;
/* ================================================================
@ -61,28 +61,28 @@ typedef struct
gsize capture_prog_len;
/* Geometry derived from SensorTypeInfo + CaptureProg */
guint16 lines_per_frame;
guint16 bytes_per_line;
guint16 lines_per_frame;
guint16 bytes_per_line;
/* Calibration parameters (derived from sensor geometry) */
guint16 key_calibration_line;
guint8 calibration_frames;
guint8 calibration_iterations;
guint16 key_calibration_line;
guint8 calibration_frames;
guint8 calibration_iterations;
/* Factory calibration values (from factory_bits subtag 3) */
guint8 *factory_calibration_values;
gsize factory_calibration_values_len;
guint8 *factory_calibration_values;
gsize factory_calibration_values_len;
/* Optional factory calibration data (from factory_bits subtag 7) */
guint8 *factory_calib_data;
gsize factory_calib_data_len;
guint8 *factory_calib_data;
gsize factory_calib_data_len;
/* Accumulated calibration data (built during calibration loop) */
guint8 *calib_data;
gsize calib_data_len;
guint8 *calib_data;
gsize calib_data_len;
/* Whether this is a line_update_type_1 device */
gboolean is_type1_device;
gboolean is_type1_device;
} ValidityCaptureState;
/* ================================================================
@ -133,21 +133,21 @@ gboolean validity_capture_decode_insn (const guint8 *data,
guint8 *n_operands);
/* Timeslot instruction opcodes */
#define TST_OP_NOOP 0
#define TST_OP_END_OF_TABLE 1
#define TST_OP_RETURN 2
#define TST_OP_CLEAR_SO 3
#define TST_OP_END_OF_DATA 4
#define TST_OP_MACRO 5
#define TST_OP_ENABLE_RX 6
#define TST_OP_IDLE_RX 7
#define TST_OP_ENABLE_SO 8
#define TST_OP_DISABLE_SO 9
#define TST_OP_INTERRUPT 10
#define TST_OP_CALL 11
#define TST_OP_FEATURES 12
#define TST_OP_REG_WRITE 13
#define TST_OP_SAMPLE 14
#define TST_OP_NOOP 0
#define TST_OP_END_OF_TABLE 1
#define TST_OP_RETURN 2
#define TST_OP_CLEAR_SO 3
#define TST_OP_END_OF_DATA 4
#define TST_OP_MACRO 5
#define TST_OP_ENABLE_RX 6
#define TST_OP_IDLE_RX 7
#define TST_OP_ENABLE_SO 8
#define TST_OP_DISABLE_SO 9
#define TST_OP_INTERRUPT 10
#define TST_OP_CALL 11
#define TST_OP_FEATURES 12
#define TST_OP_REG_WRITE 13
#define TST_OP_SAMPLE 14
#define TST_OP_SAMPLE_REPEAT 15
/*
@ -178,8 +178,8 @@ gssize validity_capture_find_nth_regwrite (const guint8 *data,
* multiply it by mult and optionally increment the address.
* Modifies data in-place. Returns TRUE on success.
*/
gboolean validity_capture_patch_timeslot_table (guint8 *data,
gsize data_len,
gboolean validity_capture_patch_timeslot_table (guint8 *data,
gsize data_len,
gboolean inc_address,
guint8 mult);
@ -210,7 +210,7 @@ gboolean validity_capture_patch_timeslot_again (guint8 *data,
* Returns a newly-allocated buffer (caller must g_free) or NULL on error.
* Sets out_len to the buffer size.
*/
guint8 *validity_capture_build_cmd_02 (const ValidityCaptureState *capture,
guint8 *validity_capture_build_cmd_02 (const ValidityCaptureState *capture,
const ValiditySensorTypeInfo *type_info,
ValidityCaptureMode mode,
gsize *out_len);
@ -230,12 +230,12 @@ guint8 *validity_capture_build_cmd_02 (const ValidityCaptureState *capture,
*
* Returns TRUE if at least subtag 3 was found.
*/
gboolean validity_capture_parse_factory_bits (const guint8 *data,
gsize data_len,
guint8 **cal_values,
gsize *cal_values_len,
guint8 **cal_data,
gsize *cal_data_len);
gboolean validity_capture_parse_factory_bits (const guint8 *data,
gsize data_len,
guint8 **cal_values,
gsize *cal_values_len,
guint8 **cal_data,
gsize *cal_data_len);
/* ================================================================
* Frame averaging
@ -268,11 +268,11 @@ guint8 *validity_capture_average_frames (const guint8 *raw_data,
* If calib_data is NULL, initializes from the frame.
* If non-NULL, combines (adds signed values, clips).
*/
void validity_capture_process_calibration (guint8 **calib_data,
gsize *calib_data_len,
const guint8 *averaged_frame,
gsize frame_len,
guint16 bytes_per_line);
void validity_capture_process_calibration (guint8 **calib_data,
gsize *calib_data_len,
const guint8 *averaged_frame,
gsize frame_len,
guint16 bytes_per_line);
/*
* Build the clean slate format for flash persistence.
@ -353,16 +353,16 @@ const guint8 *validity_capture_glow_end_cmd (gsize *out_len);
* Returns a pointer to the static blob data and sets out_len.
* Returns NULL if no matching entry is found.
*/
const guint8 *validity_capture_prog_lookup (guint8 rom_major,
guint8 rom_minor,
guint16 dev_type,
gsize *out_len);
const guint8 *validity_capture_prog_lookup (guint8 rom_major,
guint8 rom_minor,
guint16 dev_type,
gsize *out_len);
/* ================================================================
* Capture state lifecycle
* ================================================================ */
void validity_capture_state_init (ValidityCaptureState *state);
void validity_capture_state_init (ValidityCaptureState *state);
void validity_capture_state_clear (ValidityCaptureState *state);
/*
@ -379,18 +379,18 @@ gboolean validity_capture_state_setup (ValidityCaptureState *state,
gsize factory_bits_len);
/* Chunk type IDs used in capture programs */
#define CAPT_CHUNK_REPLY_CONFIG 0x0017
#define CAPT_CHUNK_FINGER_DETECT 0x0026
#define CAPT_CHUNK_IMAGE_RECON 0x002e
#define CAPT_CHUNK_2D_PARAMS 0x002f
#define CAPT_CHUNK_LINE_UPDATE 0x0030
#define CAPT_CHUNK_TIMESLOT_2D 0x0034
#define CAPT_CHUNK_TS_OFFSET 0x0029
#define CAPT_CHUNK_TS_FD_OFFSET 0x0035
#define CAPT_CHUNK_LINE_UPDATE_XFORM 0x0043
#define CAPT_CHUNK_INTERLEAVE 0x0044
#define CAPT_CHUNK_WTF 0x004e
#define CAPT_CHUNK_REPLY_CONFIG 0x0017
#define CAPT_CHUNK_FINGER_DETECT 0x0026
#define CAPT_CHUNK_IMAGE_RECON 0x002e
#define CAPT_CHUNK_2D_PARAMS 0x002f
#define CAPT_CHUNK_LINE_UPDATE 0x0030
#define CAPT_CHUNK_TIMESLOT_2D 0x0034
#define CAPT_CHUNK_TS_OFFSET 0x0029
#define CAPT_CHUNK_TS_FD_OFFSET 0x0035
#define CAPT_CHUNK_LINE_UPDATE_XFORM 0x0043
#define CAPT_CHUNK_INTERLEAVE 0x0044
#define CAPT_CHUNK_WTF 0x004e
/* Capture program cookie for the ACM Config chunk */
#define CAPT_CHUNK_ACM_CONFIG 0x002a
#define CAPT_CHUNK_CEM_CONFIG 0x002c
#define CAPT_CHUNK_ACM_CONFIG 0x002a
#define CAPT_CHUNK_CEM_CONFIG 0x002c

View file

@ -129,8 +129,8 @@ validity_db_build_cmd_get_user_storage (const gchar *name,
/* cmd 0x4A: Get user by dbid
* Format: 0x4A | dbid(2LE) | 0(2LE) | 0(2LE) */
guint8 *
validity_db_build_cmd_get_user (guint16 dbid,
gsize *out_len)
validity_db_build_cmd_get_user (guint16 dbid,
gsize *out_len)
{
guint8 *cmd = g_new0 (guint8, 7);
@ -166,10 +166,10 @@ validity_db_build_cmd_lookup_user (guint16 storage_dbid,
}
/* cmd 0x49: Get record value
* Format: 0x49 | dbid(2LE) */
* Format: 0x49 | dbid(2LE) */
guint8 *
validity_db_build_cmd_get_record_value (guint16 dbid,
gsize *out_len)
validity_db_build_cmd_get_record_value (guint16 dbid,
gsize *out_len)
{
guint8 *cmd = g_new0 (guint8, 3);
@ -183,8 +183,8 @@ validity_db_build_cmd_get_record_value (guint16 dbid,
/* cmd 0x46: Get record children
* Format: 0x46 | dbid(2LE) */
guint8 *
validity_db_build_cmd_get_record_children (guint16 dbid,
gsize *out_len)
validity_db_build_cmd_get_record_children (guint16 dbid,
gsize *out_len)
{
guint8 *cmd = g_new0 (guint8, 3);
@ -223,8 +223,8 @@ validity_db_build_cmd_new_record (guint16 parent,
/* cmd 0x48: Delete record
* Format: 0x48 | dbid(2LE) */
guint8 *
validity_db_build_cmd_del_record (guint16 dbid,
gsize *out_len)
validity_db_build_cmd_del_record (guint16 dbid,
gsize *out_len)
{
guint8 *cmd = g_new0 (guint8, 3);
@ -266,8 +266,8 @@ validity_db_build_cmd_create_enrollment (gboolean start,
/* cmd 0x68: Enrollment update start
* PY format: pack('<BLL', 0x68, key, 0) 9 bytes: 0x68, key(4LE), 0(4LE) */
guint8 *
validity_db_build_cmd_enrollment_update_start (guint32 key,
gsize *out_len)
validity_db_build_cmd_enrollment_update_start (guint32 key,
gsize *out_len)
{
guint8 *cmd = g_new0 (guint8, 9);
@ -437,9 +437,9 @@ validity_db_parse_info (const guint8 *data,
* Format: recid(2LE) usercnt(2LE) namesz(2LE) unknown(2LE)
* usrtab[usercnt * 4 bytes] name[namesz bytes] */
gboolean
validity_db_parse_user_storage (const guint8 *data,
gsize data_len,
ValidityUserStorage *out)
validity_db_parse_user_storage (const guint8 *data,
gsize data_len,
ValidityUserStorage *out)
{
FpiByteReader reader;
guint16 name_sz, unknown;
@ -499,9 +499,9 @@ validity_db_parse_user_storage (const guint8 *data,
* Format: recid(2LE) fingercnt(2LE) unknown(2LE) identitysz(2LE)
* fingertab[8 * fingercnt] identity[identitysz] */
gboolean
validity_db_parse_user (const guint8 *data,
gsize data_len,
ValidityUser *out)
validity_db_parse_user (const guint8 *data,
gsize data_len,
ValidityUser *out)
{
FpiByteReader reader;
guint16 unknown, identity_sz;
@ -561,9 +561,9 @@ validity_db_parse_user (const guint8 *data,
/* Parse record value response (cmd 0x49)
* Format: dbid(2LE) type(2LE) storage(2LE) sz(2LE) pad(2bytes) value[sz] */
gboolean
validity_db_parse_record_value (const guint8 *data,
gsize data_len,
ValidityDbRecord *out)
validity_db_parse_record_value (const guint8 *data,
gsize data_len,
ValidityDbRecord *out)
{
FpiByteReader reader;
guint16 sz;
@ -611,9 +611,9 @@ validity_db_parse_record_value (const guint8 *data,
* Format: dbid(2LE) type(2LE) storage(2LE) sz(2LE) cnt(2LE) pad(2bytes)
* children[cnt * 4 bytes: dbid(2LE) type(2LE)] */
gboolean
validity_db_parse_record_children (const guint8 *data,
gsize data_len,
ValidityRecordChildren *out)
validity_db_parse_record_children (const guint8 *data,
gsize data_len,
ValidityRecordChildren *out)
{
FpiByteReader reader;
guint16 sz, pad;

View file

@ -33,38 +33,38 @@
/* ================================================================
* 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
#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
#define VALIDITY_IDENTITY_TYPE_SID 3
/* Minimum size for encoded identity (Windows union minimum = 0x4c) */
#define VALIDITY_IDENTITY_MIN_SIZE 0x4C
#define VALIDITY_IDENTITY_MIN_SIZE 0x4C
/* Storage name used by the sensor's DB */
#define VALIDITY_STORAGE_NAME "StgWindsor"
#define VALIDITY_STORAGE_NAME "StgWindsor"
/* Flash partition for calibration data */
#define VALIDITY_FLASH_CALIBRATION_PARTITION 6
#define VALIDITY_FLASH_CALIBRATION_PARTITION 6
/* Clean slate flash header magic */
#define VALIDITY_CLEAN_SLATE_MAGIC 0x5002
#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 */
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;
@ -111,11 +111,11 @@ typedef struct
* ================================================================ */
typedef struct
{
guint16 dbid;
guint16 type;
guint16 storage;
guint8 *value; /* owned, g_free */
gsize value_len;
guint16 dbid;
guint16 type;
guint16 storage;
guint8 *value; /* owned, g_free */
gsize value_len;
} ValidityDbRecord;
/* ================================================================
@ -129,11 +129,11 @@ typedef struct
typedef struct
{
guint16 dbid;
guint16 type;
guint16 storage;
guint16 child_count;
ValidityRecordChild *children; /* owned array */
guint16 dbid;
guint16 type;
guint16 storage;
guint16 child_count;
ValidityRecordChild *children; /* owned array */
} ValidityRecordChildren;
/* ================================================================
@ -168,8 +168,8 @@ 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);
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,
@ -178,12 +178,12 @@ guint8 *validity_db_build_cmd_lookup_user (guint16 storage_dbid,
gsize *out_len);
/* cmd 0x49: Get record value */
guint8 *validity_db_build_cmd_get_record_value (guint16 dbid,
gsize *out_len);
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);
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,
@ -194,8 +194,8 @@ guint8 *validity_db_build_cmd_new_record (guint16 parent,
gsize *out_len);
/* cmd 0x48: Delete record */
guint8 *validity_db_build_cmd_del_record (guint16 dbid,
gsize *out_len);
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);
@ -211,21 +211,21 @@ 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_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_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_value (const guint8 *data,
gsize data_len,
ValidityDbRecord *out);
gboolean validity_db_parse_record_children (const guint8 *data,
gsize data_len,
ValidityRecordChildren *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,
@ -268,8 +268,8 @@ 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);
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,
@ -300,4 +300,5 @@ guint8 *validity_db_build_cmd_match_cleanup (gsize *out_len);
* db_write_enable blob access
* ================================================================ */
const guint8 *validity_db_get_write_enable_blob (guint dev_type, gsize *out_len);
const guint8 *validity_db_get_write_enable_blob (guint dev_type,
gsize *out_len);

View file

@ -104,13 +104,17 @@ interrupt_cb (FpiUsbTransfer *transfer,
int_type = transfer->buffer[0];
if (transfer->actual_length >= 5)
fp_dbg ("Interrupt: type=0x%02x bytes=[%02x %02x %02x %02x %02x] (len=%" G_GSSIZE_FORMAT ")",
int_type, transfer->buffer[0], transfer->buffer[1],
transfer->buffer[2], transfer->buffer[3], transfer->buffer[4],
transfer->actual_length);
{
fp_dbg ("Interrupt: type=0x%02x bytes=[%02x %02x %02x %02x %02x] (len=%" G_GSSIZE_FORMAT ")",
int_type, transfer->buffer[0], transfer->buffer[1],
transfer->buffer[2], transfer->buffer[3], transfer->buffer[4],
transfer->actual_length);
}
else
fp_dbg ("Interrupt: type=0x%02x (len=%" G_GSSIZE_FORMAT ")",
int_type, transfer->actual_length);
{
fp_dbg ("Interrupt: type=0x%02x (len=%" G_GSSIZE_FORMAT ")",
int_type, transfer->actual_length);
}
/* Check if this is the interrupt we're waiting for */
if (int_type == (guint8) target_state)
@ -126,10 +130,8 @@ interrupt_cb (FpiUsbTransfer *transfer,
if (int_type == 3 && transfer->actual_length >= 3)
{
if (!(transfer->buffer[2] & VALIDITY_INT_SCAN_COMPLETE))
{
/* Not scan complete yet, keep waiting */
goto read_again;
}
/* Not scan complete yet, keep waiting */
goto read_again;
/* Scan fully complete — reset retry counter */
self->scan_incomplete_count = 0;
}
@ -223,9 +225,9 @@ enrollment_update_result_clear (EnrollmentUpdateResult *r)
}
gboolean
parse_enrollment_update_response (const guint8 *data,
gsize data_len,
EnrollmentUpdateResult *result)
parse_enrollment_update_response (const guint8 *data,
gsize data_len,
EnrollmentUpdateResult *result)
{
gsize pos = 0;
guint16 declared_len;
@ -339,8 +341,8 @@ enroll_run_state (FpiSsm *ssm,
if (self->cmd_response_status != VCSFW_STATUS_OK ||
!self->cmd_response_data ||
!validity_db_parse_user_storage (self->cmd_response_data,
self->cmd_response_len,
&self->list_storage))
self->cmd_response_len,
&self->list_storage))
{
/* No storage or parse error — skip cleanup, go to enrollment */
fpi_ssm_jump_to_state (ssm, ENROLL_START);
@ -525,17 +527,13 @@ enroll_run_state (FpiSsm *ssm,
case ENROLL_CAPTURE_STOP_RECV:
/* PY: no glow_end after capture — LED stays on. */
if (self->scan_incomplete_count > 0)
{
/* Incomplete scan: retry after a brief delay.
* glow_start at the top of the loop will reinitialize.
* PY: in the except block, just retries the whole loop. */
fpi_ssm_jump_to_state_delayed (ssm, ENROLL_LED_ON, 3000);
}
/* Incomplete scan: retry after a brief delay.
* glow_start at the top of the loop will reinitialize.
* PY: in the except block, just retries the whole loop. */
fpi_ssm_jump_to_state_delayed (ssm, ENROLL_LED_ON, 3000);
else
{
/* Good scan — proceed to enrollment_update_start */
fpi_ssm_next_state (ssm);
}
/* Good scan — proceed to enrollment_update_start */
fpi_ssm_next_state (ssm);
break;
case ENROLL_UPDATE_START:

View file

@ -32,23 +32,23 @@
/* ---- Constants ---- */
#define FWEXT_CHUNK_SIZE 0x1000 /* 4 KB per write_flash chunk */
#define FWEXT_SIGNATURE_SIZE 256 /* RSA signature length */
#define FWEXT_HEADER_DELIMITER 0x1A /* .xpfwext header end marker */
#define FWEXT_CHUNK_SIZE 0x1000 /* 4 KB per write_flash chunk */
#define FWEXT_SIGNATURE_SIZE 256 /* RSA signature length */
#define FWEXT_HEADER_DELIMITER 0x1A /* .xpfwext header end marker */
#define FWEXT_HW_REG_WRITE_ADDR 0x8000205C
#define FWEXT_HW_REG_WRITE_VALUE 7
#define FWEXT_HW_REG_READ_ADDR 0x80002080
#define FWEXT_HW_REG_WRITE_ADDR 0x8000205C
#define FWEXT_HW_REG_WRITE_VALUE 7
#define FWEXT_HW_REG_READ_ADDR 0x80002080
/* Firmware partition */
#define FWEXT_PARTITION 2
#define FWEXT_PARTITION 2
/* Reboot command: 0x05 0x02 0x00 */
#define VCSFW_CMD_REBOOT 0x05
#define VCSFW_REBOOT_SUBCMD 0x02
#define VCSFW_CMD_REBOOT 0x05
#define VCSFW_REBOOT_SUBCMD 0x02
/* Cleanup command (call_cleanups): 0x1a */
#define VCSFW_CMD_CLEANUP 0x1A
#define VCSFW_CMD_CLEANUP 0x1A
/* ---- Firmware file search paths ---- */
@ -67,10 +67,10 @@ static const gchar *firmware_search_paths[] = {
* ================================================================ */
gboolean
validity_fwext_parse_fw_info (const guint8 *data,
gsize data_len,
guint16 status,
ValidityFwInfo *info)
validity_fwext_parse_fw_info (const guint8 *data,
gsize data_len,
guint16 status,
ValidityFwInfo *info)
{
memset (info, 0, sizeof (*info));
@ -143,9 +143,9 @@ validity_fwext_get_firmware_name (guint16 vid,
}
gchar *
validity_fwext_find_firmware (guint16 vid,
guint16 pid,
GError **error)
validity_fwext_find_firmware (guint16 vid,
guint16 pid,
GError **error)
{
const gchar *filename = validity_fwext_get_firmware_name (vid, pid);
@ -238,10 +238,10 @@ validity_fwext_file_clear (ValidityFwextFile *fwext)
* ================================================================ */
void
validity_fwext_build_write_hw_reg32 (guint32 addr,
guint32 value,
guint8 *cmd,
gsize *cmd_len)
validity_fwext_build_write_hw_reg32 (guint32 addr,
guint32 value,
guint8 *cmd,
gsize *cmd_len)
{
/* pack('<BLLB', 0x08, addr, val, 4) = 10 bytes */
cmd[0] = VCSFW_CMD_WRITE_HW_REG32;
@ -252,9 +252,9 @@ validity_fwext_build_write_hw_reg32 (guint32 addr,
}
void
validity_fwext_build_read_hw_reg32 (guint32 addr,
guint8 *cmd,
gsize *cmd_len)
validity_fwext_build_read_hw_reg32 (guint32 addr,
guint8 *cmd,
gsize *cmd_len)
{
/* pack('<BLB', 0x07, addr, 4) = 6 bytes */
cmd[0] = VCSFW_CMD_READ_HW_REG32;
@ -313,8 +313,8 @@ validity_fwext_build_write_fw_sig (guint8 partition,
}
void
validity_fwext_build_reboot (guint8 *cmd,
gsize *cmd_len)
validity_fwext_build_reboot (guint8 *cmd,
gsize *cmd_len)
{
/* b'\x05\x02\x00' */
cmd[0] = VCSFW_CMD_REBOOT;
@ -328,9 +328,9 @@ validity_fwext_build_reboot (guint8 *cmd,
* ================================================================ */
const guint8 *
validity_fwext_get_db_write_enable (guint16 vid,
guint16 pid,
gsize *len)
validity_fwext_get_db_write_enable (guint16 vid,
guint16 pid,
gsize *len)
{
const ValidityDeviceDesc *desc = validity_hal_device_lookup_by_pid (vid, pid);
@ -492,8 +492,8 @@ validity_fwext_upload_run_state (FpiSsm *ssm,
{
gsize dbe_len;
const guint8 *dbe = validity_fwext_get_db_write_enable (ud->vid,
ud->pid,
&dbe_len);
ud->pid,
&dbe_len);
if (dbe == NULL || dbe_len == 0)
{
@ -581,15 +581,11 @@ validity_fwext_upload_run_state (FpiSsm *ssm,
}
if (ud->write_offset < ud->fwext.payload_len)
{
/* More chunks to write -- loop back to db_write_enable */
fpi_ssm_jump_to_state (ssm, FWEXT_SEND_DB_WRITE_ENABLE);
}
/* More chunks to write -- loop back to db_write_enable */
fpi_ssm_jump_to_state (ssm, FWEXT_SEND_DB_WRITE_ENABLE);
else
{
/* All chunks written -- proceed to signature */
fpi_ssm_next_state (ssm);
}
/* All chunks written -- proceed to signature */
fpi_ssm_next_state (ssm);
break;
case FWEXT_SEND_WRITE_SIGNATURE:
@ -684,7 +680,7 @@ validity_fwext_upload_ssm_new (FpDevice *dev)
FwextUploadData *ud;
ssm = fpi_ssm_new (dev, validity_fwext_upload_run_state,
FWEXT_NUM_STATES);
FWEXT_NUM_STATES);
ud = g_new0 (FwextUploadData, 1);
fpi_ssm_set_data (ssm, ud, fwext_upload_data_free);

View file

@ -35,11 +35,11 @@ typedef struct
typedef struct
{
gboolean loaded;
guint16 major;
guint16 minor;
guint32 buildtime;
guint16 module_count;
gboolean loaded;
guint16 major;
guint16 minor;
guint32 buildtime;
guint16 module_count;
ValidityFwModule modules[32];
} ValidityFwInfo;
@ -84,56 +84,56 @@ typedef enum {
/* ---- API ---- */
gboolean validity_fwext_parse_fw_info (const guint8 *data,
gsize data_len,
guint16 status,
ValidityFwInfo *info);
gboolean validity_fwext_parse_fw_info (const guint8 *data,
gsize data_len,
guint16 status,
ValidityFwInfo *info);
gboolean validity_fwext_load_file (const gchar *filename,
ValidityFwextFile *fwext,
GError **error);
gboolean validity_fwext_load_file (const gchar *filename,
ValidityFwextFile *fwext,
GError **error);
void validity_fwext_file_clear (ValidityFwextFile *fwext);
void validity_fwext_file_clear (ValidityFwextFile *fwext);
const gchar *validity_fwext_get_firmware_name (guint16 vid,
guint16 pid);
gchar *validity_fwext_find_firmware (guint16 vid,
guint16 pid,
GError **error);
gchar *validity_fwext_find_firmware (guint16 vid,
guint16 pid,
GError **error);
void validity_fwext_build_write_hw_reg32 (guint32 addr,
guint32 value,
guint8 *cmd,
gsize *cmd_len);
void validity_fwext_build_write_hw_reg32 (guint32 addr,
guint32 value,
guint8 *cmd,
gsize *cmd_len);
void validity_fwext_build_read_hw_reg32 (guint32 addr,
guint8 *cmd,
gsize *cmd_len);
void validity_fwext_build_read_hw_reg32 (guint32 addr,
guint8 *cmd,
gsize *cmd_len);
gboolean validity_fwext_parse_read_hw_reg32 (const guint8 *data,
gsize data_len,
guint32 *value);
gboolean validity_fwext_parse_read_hw_reg32 (const guint8 *data,
gsize data_len,
guint32 *value);
void validity_fwext_build_write_flash (guint8 partition,
guint32 offset,
const guint8 *data,
gsize data_len,
guint8 *cmd,
gsize *cmd_len);
void validity_fwext_build_write_flash (guint8 partition,
guint32 offset,
const guint8 *data,
gsize data_len,
guint8 *cmd,
gsize *cmd_len);
void validity_fwext_build_write_fw_sig (guint8 partition,
const guint8 *signature,
gsize sig_len,
guint8 *cmd,
gsize *cmd_len);
void validity_fwext_build_write_fw_sig (guint8 partition,
const guint8 *signature,
gsize sig_len,
guint8 *cmd,
gsize *cmd_len);
void validity_fwext_build_reboot (guint8 *cmd,
gsize *cmd_len);
void validity_fwext_build_reboot (guint8 *cmd,
gsize *cmd_len);
const guint8 *validity_fwext_get_db_write_enable (guint16 vid,
guint16 pid,
gsize *len);
const guint8 *validity_fwext_get_db_write_enable (guint16 vid,
guint16 pid,
gsize *len);
/* SSM entry point for upload state machine */
void validity_fwext_upload_run_state (FpiSsm *ssm,
@ -141,4 +141,4 @@ void validity_fwext_upload_run_state (FpiSsm *ssm,
/* Create the fwext upload SSM with data attached.
* Caller starts it via fpi_ssm_start(). */
FpiSsm *validity_fwext_upload_ssm_new (FpDevice *dev);
FpiSsm *validity_fwext_upload_ssm_new (FpDevice *dev);

View file

@ -162,10 +162,8 @@ const ValidityDeviceDesc *
validity_hal_device_lookup_by_pid (guint16 vid, guint16 pid)
{
for (gsize i = 0; i < G_N_ELEMENTS (device_table); i++)
{
if (device_table[i].vid == vid && device_table[i].pid == pid)
return &device_table[i];
}
if (device_table[i].vid == vid && device_table[i].pid == pid)
return &device_table[i];
return NULL;
}

View file

@ -80,10 +80,10 @@ typedef struct
} ValidityDeviceDesc;
/* Number of flash partition entries in the standard layout */
#define VALIDITY_FLASH_NUM_PARTITIONS 5
#define VALIDITY_FLASH_NUM_PARTITIONS 5
/* Partition signature size (RSA-2048) */
#define VALIDITY_PARTITION_SIG_SIZE 256
#define VALIDITY_PARTITION_SIG_SIZE 256
/* Look up device descriptor by ValidityDeviceType enum.
* Returns NULL if dev_type is out of range. */

View file

@ -79,7 +79,7 @@ validity_pair_state_free (ValidityPairState *state)
* [partition_entries: count * 12 bytes each]
* ================================================================ */
#define FLASH_INFO_HEADER_SIZE 14 /* 7 × guint16 */
#define FLASH_INFO_HEADER_SIZE 14 /* 7 × guint16 */
gboolean
validity_pair_parse_flash_info (const guint8 *data,
@ -130,7 +130,7 @@ validity_pair_parse_flash_info (const guint8 *data,
void
validity_pair_serialize_partition (const ValidityPartition *part,
guint8 *out)
guint8 *out)
{
guint8 entry[12];
@ -286,7 +286,7 @@ derive_hs_signing_key (void)
* ================================================================ */
/* Certificate body size: 8 + 32 + 36 + 32 + 76 = 184 bytes */
#define CERT_BODY_SIZE 184
#define CERT_BODY_SIZE 184
guint8 *
validity_pair_make_cert (const guint8 *client_public_x,
@ -362,6 +362,7 @@ validity_pair_encrypt_key (const guint8 *client_private,
{
/* Build plaintext: x + y + d = 96 bytes */
guint8 plaintext[96 + 16]; /* + max PKCS7 padding */
memcpy (plaintext, client_public_x, 32);
memcpy (plaintext + 32, client_public_y, 32);
memcpy (plaintext + 64, client_private, 32);
@ -439,19 +440,20 @@ validity_pair_encrypt_key (const guint8 *client_private,
guint8 *
validity_pair_build_partition_flash_cmd (const ValidityFlashIcParams *flash_ic,
const ValidityFlashLayout *layout,
const guint8 *client_public_x,
const guint8 *client_public_y,
gsize *out_len)
const ValidityFlashLayout *layout,
const guint8 *client_public_x,
const guint8 *client_public_y,
gsize *out_len)
{
/* Build flash IC params body (hdr 0) */
guint8 ic_body[12];
serialize_flash_params (flash_ic, ic_body);
gsize hdr0_len;
g_autofree guint8 *hdr0 = build_header (VALIDITY_HDR_FLASH_IC,
ic_body, sizeof (ic_body),
&hdr0_len);
ic_body, sizeof (ic_body),
&hdr0_len);
/* Build partition table body (hdr 1):
* [partition entries (48 bytes each)] + [RSA signature (256 bytes)] */
@ -460,38 +462,36 @@ validity_pair_build_partition_flash_cmd (const ValidityFlashIcParams *flash_ic,
g_autofree guint8 *ptbl_body = g_malloc0 (ptbl_body_len);
for (gsize i = 0; i < layout->num_partitions; i++)
{
validity_pair_serialize_partition (&layout->partitions[i],
ptbl_body + (i * VALIDITY_PARTITION_ENTRY_SIZE));
}
validity_pair_serialize_partition (&layout->partitions[i],
ptbl_body + (i * VALIDITY_PARTITION_ENTRY_SIZE));
memcpy (ptbl_body + (layout->num_partitions * VALIDITY_PARTITION_ENTRY_SIZE),
layout->partition_sig, layout->partition_sig_len);
gsize hdr1_len;
g_autofree guint8 *hdr1 = build_header (VALIDITY_HDR_PARTITION_TABLE,
ptbl_body, ptbl_body_len,
&hdr1_len);
ptbl_body, ptbl_body_len,
&hdr1_len);
/* Build client certificate (hdr 5) */
gsize cert_len;
g_autofree guint8 *cert = validity_pair_make_cert (client_public_x,
client_public_y,
&cert_len);
client_public_y,
&cert_len);
if (!cert)
return NULL;
gsize hdr5_len;
g_autofree guint8 *hdr5 = build_header (VALIDITY_HDR_CLIENT_CERT,
cert, cert_len,
&hdr5_len);
cert, cert_len,
&hdr5_len);
/* CA certificate (hdr 3) — from auto-generated constants */
gsize ca_cert_len = sizeof (ca_cert_hardcoded);
gsize hdr3_len;
g_autofree guint8 *hdr3 = build_header (VALIDITY_HDR_CA_CERT,
ca_cert_hardcoded, ca_cert_len,
&hdr3_len);
ca_cert_hardcoded, ca_cert_len,
&hdr3_len);
/* Assemble: [4f 00 00 00 00] + hdr0 + hdr1 + hdr5 + hdr3 */
gsize cmd_prefix_len = 5;
@ -502,10 +502,14 @@ validity_pair_build_partition_flash_cmd (const ValidityFlashIcParams *flash_ic,
/* bytes 1..4 are zero (already from g_malloc0) */
gsize offset = cmd_prefix_len;
memcpy (cmd + offset, hdr0, hdr0_len); offset += hdr0_len;
memcpy (cmd + offset, hdr1, hdr1_len); offset += hdr1_len;
memcpy (cmd + offset, hdr5, hdr5_len); offset += hdr5_len;
memcpy (cmd + offset, hdr3, hdr3_len); offset += hdr3_len;
memcpy (cmd + offset, hdr0, hdr0_len);
offset += hdr0_len;
memcpy (cmd + offset, hdr1, hdr1_len);
offset += hdr1_len;
memcpy (cmd + offset, hdr5, hdr5_len);
offset += hdr5_len;
memcpy (cmd + offset, hdr3, hdr3_len);
offset += hdr3_len;
*out_len = total;
return cmd;
@ -529,7 +533,7 @@ validity_pair_build_partition_flash_cmd (const ValidityFlashIcParams *flash_ic,
* Remaining: 0xff padding to 0x1000
* ================================================================ */
#define TLS_FLASH_IMAGE_SIZE 0x1000
#define TLS_FLASH_IMAGE_SIZE 0x1000
static gsize
append_flash_block (guint8 *buf, gsize offset, guint16 id,
@ -646,7 +650,7 @@ validity_pair_run_state (FpiSsm *ssm,
fp_warn ("GET_FLASH_INFO failed: status=0x%04x",
self->cmd_response_status);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
@ -657,7 +661,7 @@ validity_pair_run_state (FpiSsm *ssm,
{
fp_warn ("Failed to parse flash info");
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
@ -679,7 +683,7 @@ validity_pair_run_state (FpiSsm *ssm,
{
fp_warn ("No HAL descriptor for dev_type=%u", self->dev_type);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
return;
}
@ -765,7 +769,7 @@ validity_pair_run_state (FpiSsm *ssm,
{
fp_warn ("No HAL descriptor for dev_type=%u", self->dev_type);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
return;
}
@ -780,7 +784,7 @@ validity_pair_run_state (FpiSsm *ssm,
{
fp_warn ("No reset_blob available for this device");
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
fpi_device_error_new (FP_DEVICE_ERROR_NOT_SUPPORTED));
return;
}
@ -797,7 +801,7 @@ validity_pair_run_state (FpiSsm *ssm,
fp_warn ("reset_blob failed: status=0x%04x",
self->cmd_response_status);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
fpi_ssm_next_state (ssm);
@ -817,7 +821,7 @@ validity_pair_run_state (FpiSsm *ssm,
{
fp_warn ("ECDH key generation failed");
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
return;
}
@ -860,7 +864,7 @@ validity_pair_run_state (FpiSsm *ssm,
{
fp_warn ("Failed to build partition_flash command");
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
fpi_device_error_new (FP_DEVICE_ERROR_GENERAL));
return;
}
@ -891,7 +895,7 @@ validity_pair_run_state (FpiSsm *ssm,
fp_warn ("partition_flash failed: status=0x%04x",
self->cmd_response_status);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
@ -953,7 +957,7 @@ validity_pair_run_state (FpiSsm *ssm,
fp_warn ("CMD 0x50 failed: status=0x%04x",
self->cmd_response_status);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
@ -972,7 +976,7 @@ validity_pair_run_state (FpiSsm *ssm,
fp_warn ("CMD 0x50 response too short: %" G_GSIZE_FORMAT,
self->cmd_response_len);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
@ -1015,7 +1019,7 @@ validity_pair_run_state (FpiSsm *ssm,
memcpy (pub_uncompressed + 1, x_be, 32);
memcpy (pub_uncompressed + 33, y_be, 32);
OSSL_PARAM_BLD_push_octet_string (bld, OSSL_PKEY_PARAM_PUB_KEY,
pub_uncompressed, 65);
pub_uncompressed, 65);
OSSL_PARAM *params = OSSL_PARAM_BLD_to_param (bld);
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_from_name (NULL, "EC", NULL);
@ -1029,7 +1033,7 @@ validity_pair_run_state (FpiSsm *ssm,
{
fp_warn ("Failed to build ECDH server public key");
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
@ -1087,7 +1091,7 @@ validity_pair_run_state (FpiSsm *ssm,
}
/* Set priv_key — the TLS handshake needs the actual EC private key
* (EVP_PKEY*) to sign cert_verify. We have it as ps->client_key. */
* (EVP_PKEY*) to sign cert_verify. We have it as ps->client_key. */
if (self->tls.priv_key)
EVP_PKEY_free (self->tls.priv_key);
self->tls.priv_key = EVP_PKEY_dup (ps->client_key);
@ -1114,10 +1118,8 @@ validity_pair_run_state (FpiSsm *ssm,
/* Ignore "nothing to commit" (0x0491) status */
if (self->cmd_response_status != VCSFW_STATUS_OK &&
self->cmd_response_status != 0x0491)
{
fp_warn ("cleanups failed: status=0x%04x",
self->cmd_response_status);
}
fp_warn ("cleanups failed: status=0x%04x",
self->cmd_response_status);
fpi_ssm_next_state (ssm);
}
break;
@ -1131,8 +1133,8 @@ validity_pair_run_state (FpiSsm *ssm,
* NOTE: do NOT overwrite self->open_ssm here it must remain
* pointing to the open SSM for pair_ssm_done to work. */
FpiSsm *tls_ssm = fpi_ssm_new (dev,
validity_tls_handshake_run_state,
TLS_HS_NUM_STATES);
validity_tls_handshake_run_state,
TLS_HS_NUM_STATES);
fpi_ssm_start_subsm (ssm, tls_ssm);
}
break;
@ -1259,7 +1261,7 @@ validity_pair_run_state (FpiSsm *ssm,
fp_warn ("write_flash failed: status=0x%04x",
self->cmd_response_status);
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
fpi_device_error_new (FP_DEVICE_ERROR_PROTO));
return;
}
fpi_ssm_next_state (ssm);

View file

@ -29,7 +29,7 @@
/* Forward declaration */
typedef struct _FpiDeviceValidity FpiDeviceValidity;
typedef struct _FpiSsm FpiSsm;
typedef struct _FpiSsm FpiSsm;
/* Flash IC parameters — returned by CMD 0x3e (GET_FLASH_INFO) */
typedef struct
@ -72,25 +72,25 @@ typedef struct
} ValidityPairState;
/* Partition entry serialized format: 12 bytes data + 4 zero + 32 SHA-256 = 48 */
#define VALIDITY_PARTITION_ENTRY_SIZE 48
#define VALIDITY_PARTITION_ENTRY_SIZE 48
/* Client certificate size */
#define VALIDITY_CLIENT_CERT_SIZE 444
#define VALIDITY_CLIENT_CERT_SIZE 444
/* CMD 0x4f header IDs */
#define VALIDITY_HDR_FLASH_IC 0
#define VALIDITY_HDR_PARTITION_TABLE 1
#define VALIDITY_HDR_CA_CERT 3
#define VALIDITY_HDR_CLIENT_CERT 5
#define VALIDITY_HDR_FLASH_IC 0
#define VALIDITY_HDR_PARTITION_TABLE 1
#define VALIDITY_HDR_CA_CERT 3
#define VALIDITY_HDR_CLIENT_CERT 5
/* Encrypted private key format: 0x02 prefix + IV(16) + ciphertext(112) + HMAC(32) = 161 */
#define VALIDITY_ENCRYPTED_KEY_PREFIX 0x02
#define VALIDITY_ENCRYPTED_KEY_PREFIX 0x02
#define VALIDITY_ENCRYPTED_KEY_IV_SIZE 16
#define VALIDITY_EC_COORD_SIZE 32
#define VALIDITY_EC_COORD_SIZE 32
/* Flash partition IDs for erase during pairing */
static const guint8 pair_erase_partition_ids[] = { 1, 2, 5, 6, 4 };
#define VALIDITY_PAIR_NUM_ERASE_STEPS G_N_ELEMENTS (pair_erase_partition_ids)
#define VALIDITY_PAIR_NUM_ERASE_STEPS G_N_ELEMENTS (pair_erase_partition_ids)
/* ---- Helper functions (testable independently) ---- */
@ -103,7 +103,7 @@ static const guint8 pair_erase_partition_ids[] = { 1, 2, 5, 6, 4 };
* [id:1][type:1][access_lvl:2LE][offset:4LE][size:4LE][zeros:4][SHA256:32]
*/
void validity_pair_serialize_partition (const ValidityPartition *part,
guint8 *out);
guint8 *out);
/**
* validity_pair_build_partition_flash_cmd:
@ -277,13 +277,13 @@ typedef enum {
} ValidityPairSsmState;
/* CMD 0x1a (cleanups/commit) */
#define VCSFW_CMD_CLEANUPS 0x1a
#define VCSFW_CMD_CLEANUPS 0x1a
/* CMD 0x50 (get ECDH server params after partition_flash) */
#define VCSFW_CMD_GET_ECDH 0x50
#define VCSFW_CMD_GET_ECDH 0x50
/* Reboot: 0x05 0x02 0x00 */
#define VCSFW_CMD_REBOOT 0x05
#define VCSFW_CMD_REBOOT 0x05
/**
* validity_pair_ssm_new:

View file

@ -387,13 +387,9 @@ validity_device_info_lookup (guint16 major,
guint8 masked_ver = entry->version & entry->version_mask;
if (version == 0 || masked_ver == 0)
{
fuzzy_match = entry;
}
fuzzy_match = entry;
else if ((guint8) version == masked_ver)
{
return entry;
}
return entry;
}
return fuzzy_match;
@ -407,10 +403,8 @@ const ValiditySensorTypeInfo *
validity_sensor_type_info_lookup (guint16 sensor_type)
{
for (gsize i = 0; i < SENSOR_TYPE_INFO_TABLE_LEN; i++)
{
if (sensor_type_info_table[i].sensor_type == sensor_type)
return &sensor_type_info_table[i];
}
if (sensor_type_info_table[i].sensor_type == sensor_type)
return &sensor_type_info_table[i];
return NULL;
}

View file

@ -72,9 +72,9 @@ typedef struct
*/
typedef struct
{
ValiditySensorIdent ident;
const ValidityDeviceInfo *device_info;
const ValiditySensorTypeInfo *type_info;
ValiditySensorIdent ident;
const ValidityDeviceInfo *device_info;
const ValiditySensorTypeInfo *type_info;
/* Factory calibration bits (raw response from cmd 0x6f) */
guint8 *factory_bits;
@ -122,5 +122,5 @@ gsize validity_sensor_build_factory_bits_cmd (guint16 tag,
/* ---- Lifecycle ---- */
void validity_sensor_state_init (ValiditySensorState *state);
void validity_sensor_state_init (ValiditySensorState *state);
void validity_sensor_state_clear (ValiditySensorState *state);

View file

@ -93,6 +93,7 @@ validity_tls_prf (const guint8 *secret,
/* A(1) = HMAC(secret, seed) */
EVP_MAC_CTX *ctx = EVP_MAC_CTX_new (mac);
EVP_MAC_init (ctx, secret, secret_len, prf_params);
EVP_MAC_update (ctx, seed, seed_len);
EVP_MAC_final (ctx, a, &hmac_len, sizeof (a));
@ -174,6 +175,7 @@ validity_tls_derive_psk (ValidityTlsState *tls)
{
g_autofree gchar *product_name = NULL;
g_autofree gchar *product_serial = NULL;
g_autoptr(GError) error_name = NULL;
g_autoptr(GError) error_serial = NULL;
@ -400,6 +402,7 @@ validity_tls_wrap_app_data (ValidityTlsState *tls,
/* Sign: plaintext || HMAC(sign_key, hdr || plaintext) */
gsize signed_len = cmd_len + TLS_HMAC_SIZE;
guint8 *signed_data = g_malloc (signed_len);
memcpy (signed_data, cmd, cmd_len);
tls_hmac_sign (tls->sign_key, TLS_CONTENT_APP_DATA,
cmd, cmd_len, signed_data + cmd_len);
@ -974,6 +977,7 @@ hs_append_msg (GByteArray *buf, GChecksum *hash,
guint8 type, const guint8 *body, gsize body_len)
{
guint8 hdr[4];
hdr[0] = type;
hdr[1] = (body_len >> 16) & 0xff;
hdr[2] = (body_len >> 8) & 0xff;
@ -1172,7 +1176,7 @@ validity_tls_parse_server_hello (ValidityTlsState *tls,
const guint8 *after_sessid = after_random + 1 + sess_id_len;
guint16 suite = ((guint16) after_sessid[0] << 8) |
after_sessid[1];
after_sessid[1];
if (suite != TLS_CS_ECDH_ECDSA_AES256_CBC_SHA)
{
g_set_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_PROTO,
@ -1238,6 +1242,7 @@ validity_tls_build_client_finish (ValidityTlsState *tls, gsize *out_len)
/* ---- Generate ephemeral ECDH key pair ---- */
EVP_PKEY *params_key = NULL;
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name (NULL, "EC", NULL);
EVP_PKEY_keygen_init (pctx);
OSSL_PARAM gen_params[] = {
OSSL_PARAM_utf8_string (OSSL_PKEY_PARAM_GROUP_NAME, (char *) "prime256v1", 0),
@ -1280,7 +1285,8 @@ validity_tls_build_client_finish (ValidityTlsState *tls, gsize *out_len)
}
{
GChecksum *hc = g_checksum_copy (tls->handshake_hash);
guint8 hd[32]; gsize hl = 32;
guint8 hd[32];
gsize hl = 32;
g_checksum_get_digest (hc, hd, &hl);
g_checksum_free (hc);
GString *hex = g_string_new ("TLS hash after srv: ");
@ -1369,7 +1375,8 @@ validity_tls_build_client_finish (ValidityTlsState *tls, gsize *out_len)
g_byte_array_free (wrapped2, TRUE);
{
GChecksum *hc = g_checksum_copy (tls->handshake_hash);
guint8 hd[32]; gsize hl = 32;
guint8 hd[32];
gsize hl = 32;
g_checksum_get_digest (hc, hd, &hl);
g_checksum_free (hc);
GString *hex = g_string_new ("TLS hash after cert: ");
@ -1404,7 +1411,8 @@ validity_tls_build_client_finish (ValidityTlsState *tls, gsize *out_len)
TLS_HS_CLIENT_KEY_EXCHANGE, kex_body, kex_body_len);
{
GChecksum *hc = g_checksum_copy (tls->handshake_hash);
guint8 hd[32]; gsize hl = 32;
guint8 hd[32];
gsize hl = 32;
g_checksum_get_digest (hc, hd, &hl);
g_checksum_free (hc);
GString *hex = g_string_new ("TLS hash after kex: ");
@ -1748,8 +1756,8 @@ validity_tls_flash_read_run_state (FpiSsm *ssm,
if (!self->cmd_response_data || self->cmd_response_len == 0)
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"TLS flash read: empty response"));
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"TLS flash read: empty response"));
return;
}
@ -1851,8 +1859,8 @@ validity_tls_handshake_run_state (FpiSsm *ssm,
if (!self->cmd_response_data)
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"TLS handshake: no ServerHello response"));
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"TLS handshake: no ServerHello response"));
return;
}
@ -1896,8 +1904,8 @@ validity_tls_handshake_run_state (FpiSsm *ssm,
if (!self->cmd_response_data)
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"TLS handshake: no ServerFinish response"));
fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"TLS handshake: no ServerFinish response"));
return;
}

View file

@ -25,58 +25,58 @@
#include <openssl/ec.h>
/* TLS record content types */
#define TLS_CONTENT_CHANGE_CIPHER 0x14
#define TLS_CONTENT_HANDSHAKE 0x16
#define TLS_CONTENT_APP_DATA 0x17
#define TLS_CONTENT_CHANGE_CIPHER 0x14
#define TLS_CONTENT_HANDSHAKE 0x16
#define TLS_CONTENT_APP_DATA 0x17
/* TLS version 1.2 */
#define TLS_VERSION_MAJOR 0x03
#define TLS_VERSION_MINOR 0x03
#define TLS_VERSION_MAJOR 0x03
#define TLS_VERSION_MINOR 0x03
/* TLS handshake message types */
#define TLS_HS_CLIENT_HELLO 0x01
#define TLS_HS_SERVER_HELLO 0x02
#define TLS_HS_CERTIFICATE 0x0B
#define TLS_HS_CERT_REQUEST 0x0D
#define TLS_HS_SERVER_HELLO_DONE 0x0E
#define TLS_HS_CERT_VERIFY 0x0F
#define TLS_HS_CLIENT_HELLO 0x01
#define TLS_HS_SERVER_HELLO 0x02
#define TLS_HS_CERTIFICATE 0x0B
#define TLS_HS_CERT_REQUEST 0x0D
#define TLS_HS_SERVER_HELLO_DONE 0x0E
#define TLS_HS_CERT_VERIFY 0x0F
#define TLS_HS_CLIENT_KEY_EXCHANGE 0x10
#define TLS_HS_FINISHED 0x14
#define TLS_HS_FINISHED 0x14
/* Cipher suite */
#define TLS_CS_ECDH_ECDSA_AES256_CBC_SHA 0xC005
#define TLS_CS_ECDH_ECDSA_AES256_CBC_SHA 0xC005
/* Key/block sizes */
#define TLS_AES_KEY_SIZE 32
#define TLS_IV_SIZE 16
#define TLS_HMAC_SIZE 32
#define TLS_AES_BLOCK_SIZE 16
#define TLS_MASTER_SECRET_SIZE 48
#define TLS_KEY_BLOCK_SIZE 0x120
#define TLS_RANDOM_SIZE 32
#define TLS_VERIFY_DATA_SIZE 12
#define TLS_AES_KEY_SIZE 32
#define TLS_IV_SIZE 16
#define TLS_HMAC_SIZE 32
#define TLS_AES_BLOCK_SIZE 16
#define TLS_MASTER_SECRET_SIZE 48
#define TLS_KEY_BLOCK_SIZE 0x120
#define TLS_RANDOM_SIZE 32
#define TLS_VERIFY_DATA_SIZE 12
/* VCSFW TLS command prefix */
#define TLS_CMD_PREFIX_SIZE 4
#define TLS_CMD_PREFIX_SIZE 4
/* Flash block IDs */
#define TLS_FLASH_BLOCK_EMPTY0 0x0000
#define TLS_FLASH_BLOCK_EMPTY1 0x0001
#define TLS_FLASH_BLOCK_EMPTY2 0x0002
#define TLS_FLASH_BLOCK_CERT 0x0003
#define TLS_FLASH_BLOCK_PRIVKEY 0x0004
#define TLS_FLASH_BLOCK_CA_CERT 0x0005
#define TLS_FLASH_BLOCK_ECDH 0x0006
#define TLS_FLASH_BLOCK_END 0xFFFF
#define TLS_FLASH_BLOCK_EMPTY0 0x0000
#define TLS_FLASH_BLOCK_EMPTY1 0x0001
#define TLS_FLASH_BLOCK_EMPTY2 0x0002
#define TLS_FLASH_BLOCK_CERT 0x0003
#define TLS_FLASH_BLOCK_PRIVKEY 0x0004
#define TLS_FLASH_BLOCK_CA_CERT 0x0005
#define TLS_FLASH_BLOCK_ECDH 0x0006
#define TLS_FLASH_BLOCK_END 0xFFFF
/* Flash block header: [id:2 LE][size:2 LE][sha256:32] */
#define TLS_FLASH_BLOCK_HEADER_SIZE (2 + 2 + 32)
#define TLS_FLASH_BLOCK_HEADER_SIZE (2 + 2 + 32)
/* ECDH key blob offsets */
#define TLS_ECDH_BLOB_SIZE 0x90
#define TLS_ECDH_X_OFFSET 0x08
#define TLS_ECDH_Y_OFFSET 0x4C
#define TLS_EC_COORD_SIZE 0x20
#define TLS_ECDH_BLOB_SIZE 0x90
#define TLS_ECDH_X_OFFSET 0x08
#define TLS_ECDH_Y_OFFSET 0x4C
#define TLS_EC_COORD_SIZE 0x20
/* Forward declaration */
typedef struct _FpiDeviceValidity FpiDeviceValidity;
@ -144,41 +144,41 @@ typedef enum {
/* ---- Public API ---- */
void validity_tls_init (ValidityTlsState *tls);
void validity_tls_free (ValidityTlsState *tls);
void validity_tls_init (ValidityTlsState *tls);
void validity_tls_free (ValidityTlsState *tls);
void validity_tls_derive_psk (ValidityTlsState *tls);
void validity_tls_derive_psk (ValidityTlsState *tls);
gboolean validity_tls_parse_flash (ValidityTlsState *tls,
const guint8 *data,
gsize data_len,
GError **error);
gboolean validity_tls_parse_flash (ValidityTlsState *tls,
const guint8 *data,
gsize data_len,
GError **error);
/* PRF — exported for testing */
void validity_tls_prf (const guint8 *secret,
gsize secret_len,
const guint8 *seed,
gsize seed_len,
guint8 *output,
gsize output_len);
void validity_tls_prf (const guint8 *secret,
gsize secret_len,
const guint8 *seed,
gsize seed_len,
guint8 *output,
gsize output_len);
/* Encrypt/decrypt for TLS app data */
guint8 *validity_tls_encrypt (ValidityTlsState *tls,
const guint8 *plaintext,
gsize plaintext_len,
gsize *out_len);
guint8 *validity_tls_encrypt (ValidityTlsState *tls,
const guint8 *plaintext,
gsize plaintext_len,
gsize *out_len);
guint8 *validity_tls_decrypt (ValidityTlsState *tls,
const guint8 *ciphertext,
gsize ciphertext_len,
gsize *out_len,
GError **error);
guint8 *validity_tls_decrypt (ValidityTlsState *tls,
const guint8 *ciphertext,
gsize ciphertext_len,
gsize *out_len,
GError **error);
/* Build TLS app_data record wrapping a VCSFW command */
guint8 *validity_tls_wrap_app_data (ValidityTlsState *tls,
const guint8 *cmd,
gsize cmd_len,
gsize *out_len);
guint8 *validity_tls_wrap_app_data (ValidityTlsState *tls,
const guint8 *cmd,
gsize cmd_len,
gsize *out_len);
/* Parse TLS response, returning decrypted app_data */
guint8 *validity_tls_unwrap_response (ValidityTlsState *tls,

View file

@ -86,13 +86,17 @@ verify_interrupt_cb (FpiUsbTransfer *transfer,
int_type = transfer->buffer[0];
if (transfer->actual_length >= 5)
fp_dbg ("Verify interrupt: type=0x%02x bytes=[%02x %02x %02x %02x %02x] (len=%" G_GSSIZE_FORMAT ")",
int_type, transfer->buffer[0], transfer->buffer[1],
transfer->buffer[2], transfer->buffer[3], transfer->buffer[4],
transfer->actual_length);
{
fp_dbg ("Verify interrupt: type=0x%02x bytes=[%02x %02x %02x %02x %02x] (len=%" G_GSSIZE_FORMAT ")",
int_type, transfer->buffer[0], transfer->buffer[1],
transfer->buffer[2], transfer->buffer[3], transfer->buffer[4],
transfer->actual_length);
}
else
fp_dbg ("Verify interrupt: type=0x%02x (len=%" G_GSSIZE_FORMAT ")",
int_type, transfer->actual_length);
{
fp_dbg ("Verify interrupt: type=0x%02x (len=%" G_GSSIZE_FORMAT ")",
int_type, transfer->actual_length);
}
/* During match wait, type 3 = match found, type 5 = no match */
if (fpi_ssm_get_cur_state (ssm) == VERIFY_WAIT_MATCH_INT)
@ -524,10 +528,8 @@ verify_ssm_done (FpiSsm *ssm,
gboolean have_match = FALSE;
if (self->bulk_data && self->bulk_data_len > 0)
{
if (validity_parse_match_result (self->bulk_data, self->bulk_data_len, &match))
have_match = match.matched;
}
if (validity_parse_match_result (self->bulk_data, self->bulk_data_len, &match))
have_match = match.matched;
if (self->identify_mode)
{
@ -643,8 +645,8 @@ list_run_state (FpiSsm *ssm,
if (!self->cmd_response_data ||
!validity_db_parse_user_storage (self->cmd_response_data,
self->cmd_response_len,
&self->list_storage))
self->cmd_response_len,
&self->list_storage))
{
fp_info ("Failed to parse user storage — no enrolled prints");
fpi_ssm_jump_to_state (ssm, LIST_DONE);
@ -796,8 +798,8 @@ delete_run_state (FpiSsm *ssm,
validity_user_storage_clear (&self->list_storage);
if (!self->cmd_response_data ||
!validity_db_parse_user_storage (self->cmd_response_data,
self->cmd_response_len,
&self->list_storage))
self->cmd_response_len,
&self->list_storage))
{
fpi_ssm_mark_failed (ssm,
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
@ -963,8 +965,8 @@ clear_run_state (FpiSsm *ssm,
if (self->cmd_response_status != VCSFW_STATUS_OK ||
!self->cmd_response_data ||
!validity_db_parse_user_storage (self->cmd_response_data,
self->cmd_response_len,
&self->list_storage))
self->cmd_response_len,
&self->list_storage))
{
/* No storage or parse error — nothing to clear */
fpi_ssm_jump_to_state (ssm, CLEAR_DONE);

View file

@ -28,9 +28,9 @@
/* ---- VcsfwCmdData lifecycle ---- */
VcsfwCmdData *
vcsfw_cmd_data_new (const guint8 *cmd,
gsize cmd_len,
VcsfwCmdCallback callback)
vcsfw_cmd_data_new (const guint8 *cmd,
gsize cmd_len,
VcsfwCmdCallback callback)
{
VcsfwCmdData *data = g_new0 (VcsfwCmdData, 1);
@ -186,7 +186,7 @@ vcsfw_cmd_send (FpiDeviceValidity *self,
cmd_data = vcsfw_cmd_data_new (cmd, cmd_len, callback);
ssm = fpi_ssm_new (FP_DEVICE (self), vcsfw_cmd_run_state,
VCSFW_CMD_STATE_NUM_STATES);
VCSFW_CMD_STATE_NUM_STATES);
fpi_ssm_set_data (ssm, cmd_data, vcsfw_cmd_data_free);
self->cmd_ssm = ssm;
@ -286,11 +286,13 @@ tls_cmd_receive_cb (FpiUsbTransfer *transfer,
g_free (decrypted);
if (cmd_data->callback)
cmd_data->callback (self,
self->cmd_response_data,
self->cmd_response_len,
status,
NULL);
{
cmd_data->callback (self,
self->cmd_response_data,
self->cmd_response_len,
status,
NULL);
}
fpi_ssm_mark_completed (transfer->ssm);
}
@ -358,7 +360,7 @@ vcsfw_tls_cmd_send (FpiDeviceValidity *self,
cmd_data = vcsfw_cmd_data_new (cmd, cmd_len, callback);
ssm = fpi_ssm_new (FP_DEVICE (self), vcsfw_tls_cmd_run_state,
VCSFW_TLS_CMD_STATE_NUM_STATES);
VCSFW_TLS_CMD_STATE_NUM_STATES);
fpi_ssm_set_data (ssm, cmd_data, vcsfw_cmd_data_free);
self->cmd_ssm = ssm;
@ -372,8 +374,8 @@ vcsfw_tls_cmd_send (FpiDeviceValidity *self,
/* ---- GET_VERSION (cmd 0x01) response parser ---- */
gboolean
vcsfw_parse_version (const guint8 *data,
gsize data_len,
vcsfw_parse_version (const guint8 *data,
gsize data_len,
ValidityVersionInfo *info)
{
FpiByteReader reader;

View file

@ -23,42 +23,42 @@
#include "validity.h"
/* ---- VCSFW Command IDs (pre-TLS) ---- */
#define VCSFW_CMD_GET_VERSION 0x01
#define VCSFW_CMD_READ_HW_REG32 0x07
#define VCSFW_CMD_WRITE_HW_REG32 0x08
#define VCSFW_CMD_UNKNOWN_INIT 0x19
#define VCSFW_CMD_GET_FLASH_INFO 0x3E
#define VCSFW_CMD_READ_FLASH 0x40
#define VCSFW_CMD_WRITE_FLASH 0x41
#define VCSFW_CMD_WRITE_FW_SIG 0x42
#define VCSFW_CMD_GET_FW_INFO 0x43
#define VCSFW_CMD_PARTITION_FLASH 0x4F
#define VCSFW_CMD_GET_VERSION 0x01
#define VCSFW_CMD_READ_HW_REG32 0x07
#define VCSFW_CMD_WRITE_HW_REG32 0x08
#define VCSFW_CMD_UNKNOWN_INIT 0x19
#define VCSFW_CMD_GET_FLASH_INFO 0x3E
#define VCSFW_CMD_READ_FLASH 0x40
#define VCSFW_CMD_WRITE_FLASH 0x41
#define VCSFW_CMD_WRITE_FW_SIG 0x42
#define VCSFW_CMD_GET_FW_INFO 0x43
#define VCSFW_CMD_PARTITION_FLASH 0x4F
/* ---- VCSFW Command IDs (post-TLS, via tls.app()) ---- */
#define VCSFW_CMD_CAPTURE 0x02
#define VCSFW_CMD_CAPTURE_STOP 0x04
#define VCSFW_CMD_GLOW_START 0x39
#define VCSFW_CMD_ERASE_FLASH 0x3F
#define VCSFW_CMD_DB_INFO 0x45
#define VCSFW_CMD_CAPTURE 0x02
#define VCSFW_CMD_CAPTURE_STOP 0x04
#define VCSFW_CMD_GLOW_START 0x39
#define VCSFW_CMD_ERASE_FLASH 0x3F
#define VCSFW_CMD_DB_INFO 0x45
#define VCSFW_CMD_GET_RECORD_CHILDREN 0x46
#define VCSFW_CMD_NEW_RECORD 0x47
#define VCSFW_CMD_DEL_RECORD 0x48
#define VCSFW_CMD_GET_RECORD_VALUE 0x49
#define VCSFW_CMD_GET_USER 0x4A
#define VCSFW_CMD_GET_USER_STORAGE 0x4B
#define VCSFW_CMD_GET_PRG_STATUS 0x51
#define VCSFW_CMD_MATCH_FINGER 0x5E
#define VCSFW_CMD_GET_MATCH_RESULT 0x60
#define VCSFW_CMD_MATCH_CLEANUP 0x62
#define VCSFW_CMD_NEW_RECORD 0x47
#define VCSFW_CMD_DEL_RECORD 0x48
#define VCSFW_CMD_GET_RECORD_VALUE 0x49
#define VCSFW_CMD_GET_USER 0x4A
#define VCSFW_CMD_GET_USER_STORAGE 0x4B
#define VCSFW_CMD_GET_PRG_STATUS 0x51
#define VCSFW_CMD_MATCH_FINGER 0x5E
#define VCSFW_CMD_GET_MATCH_RESULT 0x60
#define VCSFW_CMD_MATCH_CLEANUP 0x62
#define VCSFW_CMD_ENROLLMENT_UPDATE_START 0x68
#define VCSFW_CMD_CREATE_ENROLLMENT 0x69
#define VCSFW_CMD_ENROLLMENT_UPDATE 0x6B
#define VCSFW_CMD_GET_FACTORY_BITS 0x6F
#define VCSFW_CMD_IDENTIFY_SENSOR 0x75
#define VCSFW_CMD_CREATE_ENROLLMENT 0x69
#define VCSFW_CMD_ENROLLMENT_UPDATE 0x6B
#define VCSFW_CMD_GET_FACTORY_BITS 0x6F
#define VCSFW_CMD_IDENTIFY_SENSOR 0x75
/* ---- VCSFW Response Status Codes ---- */
#define VCSFW_STATUS_OK 0x0000
#define VCSFW_STATUS_NO_FW 0xB004
#define VCSFW_STATUS_OK 0x0000
#define VCSFW_STATUS_NO_FW 0xB004
/* ---- Callback types ---- */
@ -105,9 +105,9 @@ typedef struct
void vcsfw_cmd_run_state (FpiSsm *ssm,
FpDevice *dev);
VcsfwCmdData *vcsfw_cmd_data_new (const guint8 *cmd,
gsize cmd_len,
VcsfwCmdCallback callback);
VcsfwCmdData *vcsfw_cmd_data_new (const guint8 *cmd,
gsize cmd_len,
VcsfwCmdCallback callback);
void vcsfw_cmd_data_free (gpointer data);
@ -126,6 +126,6 @@ void vcsfw_tls_cmd_send (FpiDeviceValidity *self,
gsize cmd_len,
VcsfwCmdCallback callback);
gboolean vcsfw_parse_version (const guint8 *data,
gsize data_len,
gboolean vcsfw_parse_version (const guint8 *data,
gsize data_len,
ValidityVersionInfo *info);

View file

@ -137,7 +137,7 @@ test_decode_insn_noop (void)
guint32 operands[3];
g_assert_true (validity_capture_decode_insn (data, 1, &opcode, &len,
operands, &n_ops));
operands, &n_ops));
g_assert_cmpuint (opcode, ==, TST_OP_NOOP);
g_assert_cmpuint (len, ==, 1);
g_assert_cmpuint (n_ops, ==, 0);
@ -158,7 +158,7 @@ test_decode_insn_call (void)
guint32 operands[3];
g_assert_true (validity_capture_decode_insn (data, 3, &opcode, &len,
operands, &n_ops));
operands, &n_ops));
g_assert_cmpuint (opcode, ==, TST_OP_CALL);
g_assert_cmpuint (len, ==, 3);
g_assert_cmpuint (n_ops, ==, 3);
@ -180,7 +180,7 @@ test_decode_insn_call_repeat_zero (void)
guint32 operands[3];
g_assert_true (validity_capture_decode_insn (data, 3, &opcode, &len,
operands, &n_ops));
operands, &n_ops));
g_assert_cmpuint (opcode, ==, TST_OP_CALL);
g_assert_cmpuint (operands[2], ==, 0x100);
}
@ -201,7 +201,7 @@ test_decode_insn_regwrite (void)
guint32 operands[3];
g_assert_true (validity_capture_decode_insn (data, 3, &opcode, &len,
operands, &n_ops));
operands, &n_ops));
g_assert_cmpuint (opcode, ==, TST_OP_REG_WRITE);
g_assert_cmpuint (len, ==, 3);
g_assert_cmpuint (n_ops, ==, 2);
@ -222,7 +222,7 @@ test_decode_insn_enable_rx (void)
guint32 operands[3];
g_assert_true (validity_capture_decode_insn (data, 2, &opcode, &len,
operands, &n_ops));
operands, &n_ops));
g_assert_cmpuint (opcode, ==, TST_OP_ENABLE_RX);
g_assert_cmpuint (len, ==, 2);
g_assert_cmpuint (n_ops, ==, 1);
@ -243,7 +243,7 @@ test_decode_insn_sample (void)
guint32 operands[3];
g_assert_true (validity_capture_decode_insn (data, 1, &opcode, &len,
operands, &n_ops));
operands, &n_ops));
g_assert_cmpuint (opcode, ==, TST_OP_SAMPLE);
g_assert_cmpuint (len, ==, 1);
g_assert_cmpuint (n_ops, ==, 2);
@ -269,19 +269,19 @@ test_find_nth_insn (void)
/* 1st NOOP is at offset 0 */
g_assert_cmpint (validity_capture_find_nth_insn (data, sizeof (data),
TST_OP_NOOP, 1), ==, 0);
TST_OP_NOOP, 1), ==, 0);
/* 2nd NOOP is at offset 1 */
g_assert_cmpint (validity_capture_find_nth_insn (data, sizeof (data),
TST_OP_NOOP, 2), ==, 1);
TST_OP_NOOP, 2), ==, 1);
/* 3rd NOOP is at offset 5 */
g_assert_cmpint (validity_capture_find_nth_insn (data, sizeof (data),
TST_OP_NOOP, 3), ==, 5);
TST_OP_NOOP, 3), ==, 5);
/* 1st Call is at offset 2 */
g_assert_cmpint (validity_capture_find_nth_insn (data, sizeof (data),
TST_OP_CALL, 1), ==, 2);
TST_OP_CALL, 1), ==, 2);
/* No 2nd Call */
g_assert_cmpint (validity_capture_find_nth_insn (data, sizeof (data),
TST_OP_CALL, 2), ==, -1);
TST_OP_CALL, 2), ==, -1);
}
/* ================================================================
@ -300,13 +300,13 @@ test_find_nth_regwrite (void)
/* Find 1st write to 0x8000203C → offset 3 */
g_assert_cmpint (validity_capture_find_nth_regwrite (data, sizeof (data),
0x8000203c, 1), ==, 3);
0x8000203c, 1), ==, 3);
/* No 2nd write to 0x8000203C */
g_assert_cmpint (validity_capture_find_nth_regwrite (data, sizeof (data),
0x8000203c, 2), ==, -1);
0x8000203c, 2), ==, -1);
/* Find 1st write to 0x80002000 → offset 0 */
g_assert_cmpint (validity_capture_find_nth_regwrite (data, sizeof (data),
0x80002000, 1), ==, 0);
0x80002000, 1), ==, 0);
}
/* ================================================================
@ -326,7 +326,7 @@ test_patch_timeslot_table (void)
/* Multiply by 2, with inc_address=TRUE */
g_assert_true (validity_capture_patch_timeslot_table (data, sizeof (data),
TRUE, 2));
TRUE, 2));
/* repeat becomes 3*2=6 */
g_assert_cmpuint (data[2], ==, 6);
@ -348,7 +348,7 @@ test_patch_timeslot_table_no_mult_for_repeat1 (void)
};
g_assert_true (validity_capture_patch_timeslot_table (data, sizeof (data),
TRUE, 4));
TRUE, 4));
/* repeat stays 1 (not multiplied because <= 1) */
g_assert_cmpuint (data[2], ==, 1);
/* address NOT incremented */
@ -366,7 +366,7 @@ test_bitpack_uniform (void)
{
guint8 values[] = { 0x42, 0x42, 0x42, 0x42 };
guint8 v0, v1;
gsize out_len;
gsize out_len;
guint8 *packed = validity_capture_bitpack (values, 4, &v0, &v1, &out_len);
@ -389,7 +389,7 @@ test_bitpack_range (void)
{
guint8 values[] = { 10, 11, 12, 13 };
guint8 v0, v1;
gsize out_len;
gsize out_len;
guint8 *packed = validity_capture_bitpack (values, 4, &v0, &v1, &out_len);
@ -500,6 +500,7 @@ test_factory_bits_no_subtag3 (void)
{
/* Build response with only subtag=7 (no subtag=3) */
guint8 buf[32];
FP_WRITE_UINT32_LE (buf, 0); /* wtf */
FP_WRITE_UINT32_LE (buf + 4, 1); /* entries=1 */
@ -515,8 +516,8 @@ test_factory_bits_no_subtag3 (void)
gsize cv_len = 0;
gboolean ok = validity_capture_parse_factory_bits (buf, 25,
&cv, &cv_len,
NULL, NULL);
&cv, &cv_len,
NULL, NULL);
g_assert_false (ok);
g_assert_null (cv);
}
@ -534,7 +535,7 @@ test_average_frames_interleave2 (void)
guint16 bytes_per_line = 4;
guint16 lines_per_calibration_data = 2;
guint16 lines_per_frame = 4; /* 2 cal lines * 2 interleave */
guint8 calibration_frames = 1;
guint8 calibration_frames = 1;
/* Single frame: 4 lines * 4 bytes = 16 bytes */
guint8 raw[] = {
@ -582,8 +583,8 @@ test_clean_slate_roundtrip (void)
gsize slate_len = 0;
guint8 *slate = validity_capture_build_clean_slate (test_data,
sizeof (test_data),
&slate_len);
sizeof (test_data),
&slate_len);
g_assert_nonnull (slate);
g_assert_cmpuint (slate_len, >, 68);
@ -641,9 +642,9 @@ test_led_commands (void)
g_assert_nonnull (start_cmd);
g_assert_nonnull (end_cmd);
/* Both should be 128 bytes (LED control payload) */
g_assert_cmpuint (start_len, ==, 128);
g_assert_cmpuint (end_len, ==, 128);
/* Both should be 125 bytes (LED control payload) */
g_assert_cmpuint (start_len, ==, 125);
g_assert_cmpuint (end_len, ==, 125);
/* Both should start with cmd byte 0x39 */
g_assert_cmpuint (start_cmd[0], ==, 0x39);
@ -663,6 +664,7 @@ test_capture_prog_lookup (void)
/* Known: firmware 6.x, dev_type 0xb5 */
const guint8 *prog = validity_capture_prog_lookup (6, 7, 0x00b5, &len);
g_assert_nonnull (prog);
g_assert_cmpuint (len, >, 0);
@ -676,9 +678,12 @@ test_capture_prog_lookup (void)
gboolean has_acm = FALSE, has_tst = FALSE, has_2d = FALSE;
for (gsize i = 0; i < n_chunks; i++)
{
if (chunks[i].type == 0x002a) has_acm = TRUE;
if (chunks[i].type == CAPT_CHUNK_TIMESLOT_2D) has_tst = TRUE;
if (chunks[i].type == CAPT_CHUNK_2D_PARAMS) has_2d = TRUE;
if (chunks[i].type == 0x002a)
has_acm = TRUE;
if (chunks[i].type == CAPT_CHUNK_TIMESLOT_2D)
has_tst = TRUE;
if (chunks[i].type == CAPT_CHUNK_2D_PARAMS)
has_2d = TRUE;
}
g_assert_true (has_acm);
g_assert_true (has_tst);
@ -737,8 +742,8 @@ test_capture_state_setup (void)
validity_capture_state_init (&state);
gboolean ok = validity_capture_state_setup (&state, type_info,
0x00b5, 6, 7,
fb->data, fb->len);
0x00b5, 6, 7,
fb->data, fb->len);
g_assert_true (ok);
g_assert_true (state.is_type1_device);
@ -795,8 +800,8 @@ test_build_cmd_02_header (void)
gsize cmd_len = 0;
guint8 *cmd = validity_capture_build_cmd_02 (&state, type_info,
VALIDITY_CAPTURE_CALIBRATE,
&cmd_len);
VALIDITY_CAPTURE_CALIBRATE,
&cmd_len);
g_assert_nonnull (cmd);
g_assert_cmpuint (cmd_len, >=, 5);
@ -823,8 +828,8 @@ test_build_cmd_02_header (void)
/* Test IDENTIFY mode: req_lines should be 0 */
cmd = validity_capture_build_cmd_02 (&state, type_info,
VALIDITY_CAPTURE_IDENTIFY,
&cmd_len);
VALIDITY_CAPTURE_IDENTIFY,
&cmd_len);
g_assert_nonnull (cmd);
g_assert_cmpuint (FP_READ_UINT16_LE (cmd + 3), ==, 0);
g_free (cmd);
@ -848,12 +853,12 @@ test_calibration_processing (void)
};
guint8 *calib = NULL;
gsize calib_len = 0;
gsize calib_len = 0;
/* First call: initializes calib_data */
validity_capture_process_calibration (&calib, &calib_len,
frame, sizeof (frame),
bytes_per_line);
frame, sizeof (frame),
bytes_per_line);
g_assert_nonnull (calib);
g_assert_cmpuint (calib_len, ==, 16);
@ -869,8 +874,8 @@ test_calibration_processing (void)
/* Second call with same frame: accumulate */
validity_capture_process_calibration (&calib, &calib_len,
frame, sizeof (frame),
bytes_per_line);
frame, sizeof (frame),
bytes_per_line);
/* add(0, 0) = 0, so data bytes still 0 */
for (int i = 8; i < 16; i++)

View file

@ -165,6 +165,7 @@ test_cmd_create_enrollment (void)
/* Start enrollment */
g_autofree guint8 *cmd_start = validity_db_build_cmd_create_enrollment (TRUE, &len);
g_assert_nonnull (cmd_start);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpuint (cmd_start[0], ==, VCSFW_CMD_CREATE_ENROLLMENT);
@ -267,6 +268,7 @@ test_cmd_get_prg_status (void)
gsize len;
g_autofree guint8 *normal = validity_db_build_cmd_get_prg_status (FALSE, &len);
g_assert_cmpuint (len, ==, 5);
g_assert_cmpuint (normal[0], ==, VCSFW_CMD_GET_PRG_STATUS);
/* Normal: 00000000 */

View file

@ -56,6 +56,22 @@ build_block (guint16 tag, const guint8 *payload, guint16 payload_len,
return buf;
}
/* Wrap raw block data with the 2-byte declared_len prefix the parser expects:
* [declared_len:2LE][blocks...]
* declared_len = blocks_len (total size of all concatenated blocks). */
static guint8 *
wrap_response (const guint8 *blocks, gsize blocks_len, gsize *out_len)
{
*out_len = 2 + blocks_len;
guint8 *buf = g_malloc (*out_len);
FP_WRITE_UINT16_LE (buf, (guint16) blocks_len);
if (blocks && blocks_len > 0)
memcpy (buf + 2, blocks, blocks_len);
return buf;
}
/* ================================================================
* T8.1: parse empty data returns TRUE, all fields NULL
* ================================================================ */
@ -65,10 +81,8 @@ test_parse_empty (void)
EnrollmentUpdateResult result;
gboolean ok = parse_enrollment_update_response (NULL, 0, &result);
g_assert_true (ok);
g_assert_null (result.header);
g_assert_null (result.template_data);
g_assert_null (result.tid);
/* Empty data (len < 2) → parser returns FALSE */
g_assert_false (ok);
}
/* ================================================================
@ -79,11 +93,13 @@ test_parse_template_block (void)
{
guint8 payload[] = { 0xDE, 0xAD, 0xBE, 0xEF };
gsize block_len;
g_autofree guint8 *data = build_block (0, payload, sizeof (payload),
&block_len);
g_autofree guint8 *block = build_block (0, payload, sizeof (payload),
&block_len);
gsize resp_len;
g_autofree guint8 *data = wrap_response (block, block_len, &resp_len);
EnrollmentUpdateResult result;
gboolean ok = parse_enrollment_update_response (data, block_len, &result);
gboolean ok = parse_enrollment_update_response (data, resp_len, &result);
g_assert_true (ok);
g_assert_nonnull (result.template_data);
@ -102,11 +118,13 @@ test_parse_header_block (void)
{
guint8 payload[] = { 0x01, 0x02, 0x03 };
gsize block_len;
g_autofree guint8 *data = build_block (1, payload, sizeof (payload),
&block_len);
g_autofree guint8 *block = build_block (1, payload, sizeof (payload),
&block_len);
gsize resp_len;
g_autofree guint8 *data = wrap_response (block, block_len, &resp_len);
EnrollmentUpdateResult result;
gboolean ok = parse_enrollment_update_response (data, block_len, &result);
gboolean ok = parse_enrollment_update_response (data, resp_len, &result);
g_assert_true (ok);
g_assert_nonnull (result.header);
@ -126,11 +144,13 @@ test_parse_tid_block (void)
{
guint8 payload[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
gsize block_len;
g_autofree guint8 *data = build_block (3, payload, sizeof (payload),
&block_len);
g_autofree guint8 *block = build_block (3, payload, sizeof (payload),
&block_len);
gsize resp_len;
g_autofree guint8 *data = wrap_response (block, block_len, &resp_len);
EnrollmentUpdateResult result;
gboolean ok = parse_enrollment_update_response (data, block_len, &result);
gboolean ok = parse_enrollment_update_response (data, resp_len, &result);
g_assert_true (ok);
g_assert_nonnull (result.tid);
@ -160,15 +180,19 @@ test_parse_multiple_blocks (void)
g_autofree guint8 *tid = build_block (3, tid_payload,
sizeof (tid_payload), &tid_len);
/* Concatenate all three blocks */
gsize total = tmpl_len + hdr_len + tid_len;
g_autofree guint8 *data = g_malloc (total);
memcpy (data, tmpl, tmpl_len);
memcpy (data + tmpl_len, hdr, hdr_len);
memcpy (data + tmpl_len + hdr_len, tid, tid_len);
/* Concatenate all three blocks, then wrap with length prefix */
gsize blocks_total = tmpl_len + hdr_len + tid_len;
g_autofree guint8 *blocks = g_malloc (blocks_total);
memcpy (blocks, tmpl, tmpl_len);
memcpy (blocks + tmpl_len, hdr, hdr_len);
memcpy (blocks + tmpl_len + hdr_len, tid, tid_len);
gsize resp_len;
g_autofree guint8 *data = wrap_response (blocks, blocks_total, &resp_len);
EnrollmentUpdateResult result;
gboolean ok = parse_enrollment_update_response (data, total, &result);
gboolean ok = parse_enrollment_update_response (data, resp_len, &result);
g_assert_true (ok);
g_assert_nonnull (result.template_data);
@ -187,14 +211,21 @@ test_parse_multiple_blocks (void)
static void
test_parse_truncated (void)
{
guint8 payload[] = { 0xAA };
gsize block_len;
g_autofree guint8 *data = build_block (0, payload, sizeof (payload),
&block_len);
/* Build a response where the declared length is consistent with data_len
* but the block content is too short for a full block to be parsed.
* declared_len = 6, so data = [06 00][tag:2][len:2][2 more bytes]
* The block_size = MAGIC_LEN + len will exceed 8 for any len > 0,
* so the parser's "pos + block_size > data_len" check will skip it. */
guint8 data[8];
FP_WRITE_UINT16_LE (data, 6); /* declared_len = 6 */
FP_WRITE_UINT16_LE (data + 2, 0); /* tag = 0 (template) */
FP_WRITE_UINT16_LE (data + 4, 10); /* len = 10 → block_size = MAGIC_LEN + 10 > 8 */
data[6] = 0;
data[7] = 0;
/* Pass data_len shorter than block_size so the block can't be read */
EnrollmentUpdateResult result;
gboolean ok = parse_enrollment_update_response (data, 10, &result);
gboolean ok = parse_enrollment_update_response (data, sizeof (data), &result);
g_assert_true (ok);
/* No fields should be populated since the block was truncated */
@ -211,11 +242,13 @@ test_parse_unknown_tag (void)
{
guint8 payload[] = { 0x99 };
gsize block_len;
g_autofree guint8 *data = build_block (42, payload, sizeof (payload),
&block_len);
g_autofree guint8 *block = build_block (42, payload, sizeof (payload),
&block_len);
gsize resp_len;
g_autofree guint8 *data = wrap_response (block, block_len, &resp_len);
EnrollmentUpdateResult result;
gboolean ok = parse_enrollment_update_response (data, block_len, &result);
gboolean ok = parse_enrollment_update_response (data, resp_len, &result);
g_assert_true (ok);
g_assert_null (result.template_data);
@ -230,6 +263,7 @@ static void
test_result_clear (void)
{
EnrollmentUpdateResult result;
result.header = g_malloc (10);
result.header_len = 10;
result.template_data = g_malloc (20);
@ -254,10 +288,12 @@ static void
test_parse_zero_length_payload (void)
{
gsize block_len;
g_autofree guint8 *data = build_block (1, NULL, 0, &block_len);
g_autofree guint8 *block = build_block (1, NULL, 0, &block_len);
gsize resp_len;
g_autofree guint8 *data = wrap_response (block, block_len, &resp_len);
EnrollmentUpdateResult result;
gboolean ok = parse_enrollment_update_response (data, block_len, &result);
gboolean ok = parse_enrollment_update_response (data, resp_len, &result);
g_assert_true (ok);
/* Tag 1 with len=0: header should be NULL (len > 0 check in parser) */
@ -270,23 +306,23 @@ main (int argc, char *argv[])
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/validity/enroll/parse-empty",
test_parse_empty);
test_parse_empty);
g_test_add_func ("/validity/enroll/parse-template-block",
test_parse_template_block);
test_parse_template_block);
g_test_add_func ("/validity/enroll/parse-header-block",
test_parse_header_block);
test_parse_header_block);
g_test_add_func ("/validity/enroll/parse-tid-block",
test_parse_tid_block);
test_parse_tid_block);
g_test_add_func ("/validity/enroll/parse-multiple-blocks",
test_parse_multiple_blocks);
test_parse_multiple_blocks);
g_test_add_func ("/validity/enroll/parse-truncated",
test_parse_truncated);
test_parse_truncated);
g_test_add_func ("/validity/enroll/parse-unknown-tag",
test_parse_unknown_tag);
test_parse_unknown_tag);
g_test_add_func ("/validity/enroll/result-clear",
test_result_clear);
test_result_clear);
g_test_add_func ("/validity/enroll/parse-zero-length-payload",
test_parse_zero_length_payload);
test_parse_zero_length_payload);
return g_test_run ();
}

View file

@ -152,7 +152,7 @@ test_fw_info_parse_truncated (void)
static void
test_xpfwext_file_parse (void)
{
g_autoptr (GError) error = NULL;
g_autoptr(GError) error = NULL;
ValidityFwextFile fwext;
gchar *tmpdir;
g_autofree gchar *path = NULL;
@ -218,7 +218,7 @@ test_xpfwext_file_parse (void)
static void
test_xpfwext_file_no_delimiter (void)
{
g_autoptr (GError) error = NULL;
g_autoptr(GError) error = NULL;
ValidityFwextFile fwext;
gchar *tmpdir;
g_autofree gchar *path = NULL;
@ -254,7 +254,7 @@ test_xpfwext_file_no_delimiter (void)
static void
test_xpfwext_file_too_short (void)
{
g_autoptr (GError) error = NULL;
g_autoptr(GError) error = NULL;
ValidityFwextFile fwext;
gchar *tmpdir;
g_autofree gchar *path = NULL;
@ -441,7 +441,8 @@ test_hw_reg_read_parse (void)
guint8 data[] = { 0x02, 0x00, 0x00, 0x00 };
gboolean ok = validity_fwext_parse_read_hw_reg32 (data, sizeof (data),
&value);
&value);
g_assert_true (ok);
g_assert_cmpuint (value, ==, 2);
@ -486,7 +487,7 @@ test_firmware_filename (void)
static void
test_missing_firmware_file (void)
{
g_autoptr (GError) error = NULL;
g_autoptr(GError) error = NULL;
/* This should fail since firmware files aren't installed in CI */
g_autofree gchar *path = validity_fwext_find_firmware (0x06cb, 0x009a,
@ -515,7 +516,7 @@ test_missing_firmware_file (void)
static void
test_unsupported_pid_firmware (void)
{
g_autoptr (GError) error = NULL;
g_autoptr(GError) error = NULL;
g_autofree gchar *path = validity_fwext_find_firmware (0x1234, 0x5678,
&error);
@ -591,53 +592,53 @@ main (int argc,
/* Firmware info parsing */
g_test_add_func ("/validity/fwext/fw-info/parse-present",
test_fw_info_parse_present);
test_fw_info_parse_present);
g_test_add_func ("/validity/fwext/fw-info/parse-absent",
test_fw_info_parse_absent);
test_fw_info_parse_absent);
g_test_add_func ("/validity/fwext/fw-info/parse-unknown-status",
test_fw_info_parse_unknown_status);
test_fw_info_parse_unknown_status);
g_test_add_func ("/validity/fwext/fw-info/parse-truncated",
test_fw_info_parse_truncated);
test_fw_info_parse_truncated);
/* File parsing */
g_test_add_func ("/validity/fwext/file/parse",
test_xpfwext_file_parse);
test_xpfwext_file_parse);
g_test_add_func ("/validity/fwext/file/no-delimiter",
test_xpfwext_file_no_delimiter);
test_xpfwext_file_no_delimiter);
g_test_add_func ("/validity/fwext/file/too-short",
test_xpfwext_file_too_short);
test_xpfwext_file_too_short);
g_test_add_func ("/validity/fwext/file/clear-idempotent",
test_file_clear_idempotent);
test_file_clear_idempotent);
/* Command format */
g_test_add_func ("/validity/fwext/cmd/write-flash",
test_flash_write_cmd_format);
test_flash_write_cmd_format);
g_test_add_func ("/validity/fwext/cmd/write-fw-sig",
test_fw_sig_cmd_format);
test_fw_sig_cmd_format);
g_test_add_func ("/validity/fwext/cmd/write-hw-reg",
test_hw_reg_write_cmd_format);
test_hw_reg_write_cmd_format);
g_test_add_func ("/validity/fwext/cmd/read-hw-reg",
test_hw_reg_read_cmd_format);
test_hw_reg_read_cmd_format);
g_test_add_func ("/validity/fwext/cmd/read-hw-reg-parse",
test_hw_reg_read_parse);
test_hw_reg_read_parse);
g_test_add_func ("/validity/fwext/cmd/reboot",
test_reboot_cmd_format);
test_reboot_cmd_format);
/* Chunk iteration */
g_test_add_func ("/validity/fwext/chunk-iteration",
test_chunk_iteration);
test_chunk_iteration);
/* Firmware filename mapping */
g_test_add_func ("/validity/fwext/firmware-name",
test_firmware_filename);
test_firmware_filename);
g_test_add_func ("/validity/fwext/find-firmware/missing",
test_missing_firmware_file);
test_missing_firmware_file);
g_test_add_func ("/validity/fwext/find-firmware/unsupported-pid",
test_unsupported_pid_firmware);
test_unsupported_pid_firmware);
/* Blob lookup */
g_test_add_func ("/validity/fwext/db-write-enable",
test_db_write_enable_blob);
test_db_write_enable_blob);
return g_test_run ();
}

View file

@ -40,7 +40,9 @@ static void
test_hal_lookup_by_pid (void)
{
/* All 4 supported devices */
struct { guint16 vid; guint16 pid; } devices[] = {
struct { guint16 vid;
guint16 pid;
} devices[] = {
{ 0x138a, 0x0090 },
{ 0x138a, 0x0097 },
{ 0x06cb, 0x009a },
@ -64,6 +66,7 @@ static void
test_hal_lookup_invalid (void)
{
const ValidityDeviceDesc *desc = validity_hal_device_lookup (99);
g_assert_null (desc);
}
@ -75,6 +78,7 @@ test_hal_lookup_by_pid_invalid (void)
{
const ValidityDeviceDesc *desc =
validity_hal_device_lookup_by_pid (0x1234, 0x5678);
g_assert_null (desc);
}
@ -113,6 +117,7 @@ static void
test_hal_pid_0090_specifics (void)
{
const ValidityDeviceDesc *desc = validity_hal_device_lookup (VALIDITY_DEV_90);
g_assert_nonnull (desc);
/* 0090 has no init_hardcoded_clean_slate */
@ -190,6 +195,7 @@ test_hal_blob_sizes (void)
{
const ValidityDeviceDesc *desc_9a =
validity_hal_device_lookup (VALIDITY_DEV_9A);
g_assert_nonnull (desc_9a);
/* 009a blobs: init=581, clean_slate=741, reset=12037, dbe=3621 */
@ -218,6 +224,7 @@ test_hal_lookup_consistency (void)
validity_hal_device_lookup (VALIDITY_DEV_9A);
const ValidityDeviceDesc *by_pid =
validity_hal_device_lookup_by_pid (0x06cb, 0x009a);
g_assert_true (by_type == by_pid);
}
@ -227,25 +234,25 @@ main (int argc, char *argv[])
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/validity/hal/lookup-all-types",
test_hal_lookup_all_types);
test_hal_lookup_all_types);
g_test_add_func ("/validity/hal/lookup-by-pid",
test_hal_lookup_by_pid);
test_hal_lookup_by_pid);
g_test_add_func ("/validity/hal/lookup-invalid",
test_hal_lookup_invalid);
test_hal_lookup_invalid);
g_test_add_func ("/validity/hal/lookup-by-pid-invalid",
test_hal_lookup_by_pid_invalid);
test_hal_lookup_by_pid_invalid);
g_test_add_func ("/validity/hal/blobs-present",
test_hal_blobs_present);
test_hal_blobs_present);
g_test_add_func ("/validity/hal/pid-0090-specifics",
test_hal_pid_0090_specifics);
test_hal_pid_0090_specifics);
g_test_add_func ("/validity/hal/clean-slate-present",
test_hal_clean_slate_present);
test_hal_clean_slate_present);
g_test_add_func ("/validity/hal/flash-layout",
test_hal_flash_layout);
test_hal_flash_layout);
g_test_add_func ("/validity/hal/blob-sizes",
test_hal_blob_sizes);
test_hal_blob_sizes);
g_test_add_func ("/validity/hal/lookup-consistency",
test_hal_lookup_consistency);
test_hal_lookup_consistency);
return g_test_run ();
}

View file

@ -34,6 +34,7 @@ test_parse_flash_info_valid (void)
* [jid0:2LE][jid1:2LE][blocks:2LE][unknown0:2LE][blocksize:2LE]
* [unknown1:2LE][pcnt:2LE] = 14 bytes minimum */
guint8 data[14];
memset (data, 0, sizeof (data));
/* jid0=0x01, jid1=0x02, blocks=0x1000, unknown0=0, blocksize=0x100,
@ -65,6 +66,7 @@ static void
test_parse_flash_info_needs_pairing (void)
{
guint8 data[14];
memset (data, 0, sizeof (data));
FP_WRITE_UINT16_LE (data + 0, 0x0001);
@ -89,6 +91,7 @@ static void
test_parse_flash_info_too_short (void)
{
guint8 data[10]; /* less than 14 bytes */
memset (data, 0, sizeof (data));
ValidityFlashIcParams ic;
@ -114,6 +117,7 @@ test_serialize_partition (void)
};
guint8 out[VALIDITY_PARTITION_ENTRY_SIZE];
validity_pair_serialize_partition (&part, out);
/* Check first 12 bytes: id(1) type(1) access_lvl(2LE) offset(4LE) size(4LE) */
@ -147,6 +151,7 @@ static void
test_make_cert_size (void)
{
guint8 pub_x[32], pub_y[32];
RAND_bytes (pub_x, 32);
RAND_bytes (pub_y, 32);
@ -205,8 +210,8 @@ test_encrypt_key_structure (void)
gsize blob_len;
g_autofree guint8 *blob = validity_pair_encrypt_key (priv, pub_x, pub_y,
enc_key, val_key,
&blob_len);
enc_key, val_key,
&blob_len);
g_assert_nonnull (blob);
/* Blob format: 0x02(1) + IV(16) + ciphertext(112) + HMAC(32) = 161 */
@ -231,8 +236,8 @@ test_encrypt_key_hmac_valid (void)
gsize blob_len;
g_autofree guint8 *blob = validity_pair_encrypt_key (priv, pub_x, pub_y,
enc_key, val_key,
&blob_len);
enc_key, val_key,
&blob_len);
g_assert_nonnull (blob);
g_assert_cmpuint (blob_len, ==, 161);
@ -260,6 +265,7 @@ test_build_partition_flash_cmd (void)
/* Use a real device descriptor for the flash layout */
const ValidityDeviceDesc *desc =
validity_hal_device_lookup (VALIDITY_DEV_9A);
g_assert_nonnull (desc);
ValidityFlashIcParams flash_ic = {
@ -295,6 +301,7 @@ static void
test_build_tls_flash_size (void)
{
ValidityPairState state;
validity_pair_state_init (&state);
/* Set up minimal test data */
@ -344,6 +351,7 @@ static void
test_build_tls_flash_blocks (void)
{
ValidityPairState state;
validity_pair_state_init (&state);
guint8 priv_blob[50];
@ -388,6 +396,7 @@ static void
test_pair_state_lifecycle (void)
{
ValidityPairState state;
validity_pair_state_init (&state);
g_assert_null (state.client_key);
@ -408,6 +417,7 @@ static void
test_pair_state_free_with_resources (void)
{
ValidityPairState state;
validity_pair_state_init (&state);
state.server_cert = g_malloc (100);
@ -447,9 +457,9 @@ test_encrypt_key_different_inputs (void)
gsize len1, len2;
g_autofree guint8 *blob1 = validity_pair_encrypt_key (priv1, pub_x, pub_y,
enc_key, val_key, &len1);
enc_key, val_key, &len1);
g_autofree guint8 *blob2 = validity_pair_encrypt_key (priv2, pub_x, pub_y,
enc_key, val_key, &len2);
enc_key, val_key, &len2);
g_assert_nonnull (blob1);
g_assert_nonnull (blob2);
@ -465,33 +475,33 @@ main (int argc, char *argv[])
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/validity/pair/parse-flash-info-valid",
test_parse_flash_info_valid);
test_parse_flash_info_valid);
g_test_add_func ("/validity/pair/parse-flash-info-needs-pairing",
test_parse_flash_info_needs_pairing);
test_parse_flash_info_needs_pairing);
g_test_add_func ("/validity/pair/parse-flash-info-too-short",
test_parse_flash_info_too_short);
test_parse_flash_info_too_short);
g_test_add_func ("/validity/pair/serialize-partition",
test_serialize_partition);
test_serialize_partition);
g_test_add_func ("/validity/pair/make-cert-size",
test_make_cert_size);
test_make_cert_size);
g_test_add_func ("/validity/pair/make-cert-deterministic",
test_make_cert_deterministic);
test_make_cert_deterministic);
g_test_add_func ("/validity/pair/encrypt-key-structure",
test_encrypt_key_structure);
test_encrypt_key_structure);
g_test_add_func ("/validity/pair/encrypt-key-hmac-valid",
test_encrypt_key_hmac_valid);
test_encrypt_key_hmac_valid);
g_test_add_func ("/validity/pair/build-partition-flash-cmd",
test_build_partition_flash_cmd);
test_build_partition_flash_cmd);
g_test_add_func ("/validity/pair/build-tls-flash-size",
test_build_tls_flash_size);
test_build_tls_flash_size);
g_test_add_func ("/validity/pair/build-tls-flash-blocks",
test_build_tls_flash_blocks);
test_build_tls_flash_blocks);
g_test_add_func ("/validity/pair/state-lifecycle",
test_pair_state_lifecycle);
test_pair_state_lifecycle);
g_test_add_func ("/validity/pair/state-free-with-resources",
test_pair_state_free_with_resources);
test_pair_state_free_with_resources);
g_test_add_func ("/validity/pair/encrypt-key-different-inputs",
test_encrypt_key_different_inputs);
test_encrypt_key_different_inputs);
return g_test_run ();
}

View file

@ -32,6 +32,7 @@ test_identify_sensor_parse (void)
/* Build synthetic response: zeroes=0, version=0x13, major=0x004a */
guint8 data[8];
FP_WRITE_UINT32_LE (&data[0], 0); /* zeroes */
FP_WRITE_UINT16_LE (&data[4], 0x0013); /* version */
FP_WRITE_UINT16_LE (&data[6], 0x004a); /* major */
@ -245,6 +246,7 @@ test_identify_then_lookup (void)
/* Simulate cmd 0x75 response for T480s: major=0x004a, version=0x13 */
guint8 data[8];
FP_WRITE_UINT32_LE (&data[0], 0);
FP_WRITE_UINT16_LE (&data[4], 0x0013);
FP_WRITE_UINT16_LE (&data[6], 0x004a);
@ -315,33 +317,33 @@ main (int argc, char *argv[])
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/validity/sensor/identify/parse",
test_identify_sensor_parse);
test_identify_sensor_parse);
g_test_add_func ("/validity/sensor/identify/truncated",
test_identify_sensor_parse_truncated);
test_identify_sensor_parse_truncated);
g_test_add_func ("/validity/sensor/devinfo/lookup_exact",
test_device_info_lookup_exact);
test_device_info_lookup_exact);
g_test_add_func ("/validity/sensor/devinfo/lookup_another",
test_device_info_lookup_another);
test_device_info_lookup_another);
g_test_add_func ("/validity/sensor/devinfo/lookup_unknown",
test_device_info_lookup_unknown);
test_device_info_lookup_unknown);
g_test_add_func ("/validity/sensor/devinfo/lookup_fuzzy",
test_device_info_lookup_fuzzy);
test_device_info_lookup_fuzzy);
g_test_add_func ("/validity/sensor/typeinfo/lookup",
test_sensor_type_info_lookup);
test_sensor_type_info_lookup);
g_test_add_func ("/validity/sensor/typeinfo/lookup_db",
test_sensor_type_info_lookup_db);
test_sensor_type_info_lookup_db);
g_test_add_func ("/validity/sensor/typeinfo/lookup_unknown",
test_sensor_type_info_lookup_unknown);
test_sensor_type_info_lookup_unknown);
g_test_add_func ("/validity/sensor/factory_bits/cmd_format",
test_factory_bits_cmd_format);
test_factory_bits_cmd_format);
g_test_add_func ("/validity/sensor/factory_bits/buffer_too_small",
test_factory_bits_cmd_buffer_too_small);
test_factory_bits_cmd_buffer_too_small);
g_test_add_func ("/validity/sensor/identify_then_lookup",
test_identify_then_lookup);
test_identify_then_lookup);
g_test_add_func ("/validity/sensor/state_lifecycle",
test_sensor_state_lifecycle);
test_sensor_state_lifecycle);
g_test_add_func ("/validity/sensor/calibration_blob_present",
test_calibration_blob_present);
test_calibration_blob_present);
return g_test_run ();
}

View file

@ -101,6 +101,7 @@ static void
test_encrypt_decrypt_roundtrip (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
/* Set up encryption/decryption keys (same for roundtrip test) */
@ -135,6 +136,7 @@ static void
test_encrypt_block_aligned (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
memset (tls.encryption_key, 0x55, TLS_AES_KEY_SIZE);
@ -171,6 +173,7 @@ static void
test_decrypt_invalid (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
memset (tls.decryption_key, 0x55, TLS_AES_KEY_SIZE);
@ -198,6 +201,7 @@ static void
test_psk_derivation (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
validity_tls_derive_psk (&tls);
@ -235,6 +239,7 @@ static void
test_psk_deterministic (void)
{
ValidityTlsState tls1, tls2;
validity_tls_init (&tls1);
validity_tls_init (&tls2);
@ -257,6 +262,7 @@ static void
test_flash_parse_empty (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
GError *error = NULL;
@ -281,6 +287,7 @@ static void
test_flash_parse_truncated (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
GError *error = NULL;
@ -319,6 +326,7 @@ static void
test_build_client_hello (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
gsize out_len;
@ -361,6 +369,7 @@ static void
test_unwrap_invalid (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
GError *error = NULL;
@ -369,8 +378,8 @@ test_unwrap_invalid (void)
/* Short data → truncated record header */
guint8 short_data[] = { 0x17, 0x03 };
guint8 *result = validity_tls_unwrap_response (&tls, short_data,
sizeof (short_data),
&out_len, &error);
sizeof (short_data),
&out_len, &error);
g_assert_null (result);
g_assert_nonnull (error);
g_clear_error (&error);
@ -380,8 +389,8 @@ test_unwrap_invalid (void)
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
result = validity_tls_unwrap_response (&tls, app_early,
sizeof (app_early),
&out_len, &error);
sizeof (app_early),
&out_len, &error);
g_assert_null (result);
g_assert_nonnull (error);
g_clear_error (&error);
@ -401,6 +410,7 @@ static void
test_flash_parse_needs_psk (void)
{
ValidityTlsState tls_with_psk, tls_no_psk;
validity_tls_init (&tls_with_psk);
validity_tls_init (&tls_no_psk);
@ -565,6 +575,7 @@ test_flash_response_header (void)
/* Wrap it in the response header format: [size:4 LE][unk:2][data] */
guint32 data_size = sizeof (flash_data);
guint8 response[6 + sizeof (flash_data)];
FP_WRITE_UINT32_LE (response, data_size);
response[4] = 0x00; /* unknown byte 1 */
response[5] = 0x00; /* unknown byte 2 */
@ -635,6 +646,7 @@ test_server_hello_rejects_vcsfw_prefix (void)
/* Wrap in TLS record: content_type(1) + version(2) + length(2) + body */
gsize raw_tls_len = 5 + hs_len;
guint8 *raw_tls = g_malloc (raw_tls_len);
raw_tls[0] = TLS_CONTENT_HANDSHAKE; /* 0x16 */
raw_tls[1] = TLS_VERSION_MAJOR;
raw_tls[2] = TLS_VERSION_MINOR;
@ -649,7 +661,7 @@ test_server_hello_rejects_vcsfw_prefix (void)
GError *error = NULL;
gboolean result = validity_tls_parse_server_hello (&tls, raw_tls,
raw_tls_len, &error);
raw_tls_len, &error);
g_assert_no_error (error);
g_assert_true (result);
/* Verify server_random was properly extracted */
@ -703,6 +715,7 @@ static void
test_client_hello_tls_prefix (void)
{
ValidityTlsState tls;
validity_tls_init (&tls);
gsize out_len;

View file

@ -52,11 +52,11 @@ build_tlv_entry (guint8 *buf, guint16 tag, const guint8 *data, guint16 len)
* total_len(2LE) | TLV entries...
* ================================================================ */
static guint8 *
build_match_payload (guint32 user_dbid,
guint16 subtype,
build_match_payload (guint32 user_dbid,
guint16 subtype,
const guint8 *hash,
gsize hash_len,
gsize *out_len)
gsize hash_len,
gsize *out_len)
{
/* Max size: 2 (total_len) + 3 entries × (4 header + max data) */
guint8 *buf = g_new0 (guint8, 256);
@ -64,6 +64,7 @@ build_match_payload (guint32 user_dbid,
/* Tag 1: user_dbid (4 bytes LE) */
guint8 dbid_data[4];
FP_WRITE_UINT32_LE (dbid_data, user_dbid);
pos += build_tlv_entry (&buf[pos], 1, dbid_data, 4);
@ -128,6 +129,7 @@ test_parse_match_result_multi_tags (void)
/* Tag 3 first: subtype = 7 */
guint8 sub[2];
FP_WRITE_UINT16_LE (sub, 7);
pos += build_tlv_entry (&buf[pos], 3, sub, 2);
@ -188,6 +190,7 @@ test_parse_match_result_truncated (void)
/* Only 1 byte — too short for total_len */
guint8 buf1[1] = { 0x05 };
ValidityMatchResult result = { 0 };
g_assert_false (validity_parse_match_result (buf1, 1, &result));
/* total_len says 20 but only 6 bytes follow (partial TLV entry) */
@ -218,6 +221,7 @@ test_parse_match_result_unknown_tags (void)
/* Unknown tag 99 with 2 bytes of data */
guint8 unk[] = { 0x42, 0x43 };
pos += build_tlv_entry (&buf[pos], 99, unk, 2);
/* Tag 1: user_dbid = 0x0042 */
@ -481,6 +485,7 @@ static void
test_match_result_clear (void)
{
ValidityMatchResult result = { 0 };
result.matched = TRUE;
result.user_dbid = 42;
result.subtype = 5;
@ -503,49 +508,49 @@ main (int argc, char *argv[])
/* R1: parse_match_result regression tests (Issue #1: dead while loop) */
g_test_add_func ("/validity/verify/parse_match_result_valid",
test_parse_match_result_valid);
test_parse_match_result_valid);
g_test_add_func ("/validity/verify/parse_match_result_multi_tags",
test_parse_match_result_multi_tags);
test_parse_match_result_multi_tags);
g_test_add_func ("/validity/verify/parse_match_result_empty",
test_parse_match_result_empty);
test_parse_match_result_empty);
g_test_add_func ("/validity/verify/parse_match_result_truncated",
test_parse_match_result_truncated);
test_parse_match_result_truncated);
g_test_add_func ("/validity/verify/parse_match_result_unknown_tags",
test_parse_match_result_unknown_tags);
test_parse_match_result_unknown_tags);
g_test_add_func ("/validity/verify/match_result_clear",
test_match_result_clear);
test_match_result_clear);
/* R2: identity builder NULL regression (Issue #2: NULL crash) */
g_test_add_func ("/validity/verify/build_identity_null",
test_build_identity_null);
test_build_identity_null);
g_test_add_func ("/validity/verify/build_identity_valid_uuid",
test_build_identity_valid_uuid);
test_build_identity_valid_uuid);
/* R3: gallery matching by subtype (Issue #3: always returned first) */
g_test_add_func ("/validity/verify/gallery_match_by_subtype",
test_gallery_match_by_subtype);
test_gallery_match_by_subtype);
g_test_add_func ("/validity/verify/gallery_match_fallback",
test_gallery_match_fallback);
test_gallery_match_fallback);
g_test_add_func ("/validity/verify/gallery_match_empty",
test_gallery_match_empty);
test_gallery_match_empty);
/* R4: struct field separation (Issue #4: field abuse) */
g_test_add_func ("/validity/verify/struct_separate_fields",
test_struct_separate_fields);
test_struct_separate_fields);
/* R5: del_record command format (Issue #5: delete SSM non-functional) */
g_test_add_func ("/validity/verify/del_record_format",
test_del_record_format);
test_del_record_format);
/* R6: match_finger single allocation (Issue #6: double alloc) */
g_test_add_func ("/validity/verify/match_finger_size",
test_match_finger_size);
test_match_finger_size);
/* R7: clear/delete storage SSM states (Issue #7: stub) */
g_test_add_func ("/validity/verify/clear_storage_states",
test_clear_storage_states_exist);
test_clear_storage_states_exist);
g_test_add_func ("/validity/verify/delete_states",
test_delete_states_exist);
test_delete_states_exist);
return g_test_run ();
}