mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2026-05-11 10:48:39 +02:00
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:
parent
a486b58c5a
commit
4bf976c7b5
29 changed files with 943 additions and 849 deletions
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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++)
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue