mirror of
https://gitlab.freedesktop.org/libfprint/libfprint.git
synced 2025-11-15 07:38:12 +00:00
Compare commits
6 Commits
feature/sd
...
b0ce1291de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0ce1291de | ||
|
|
bef518281a | ||
|
|
8000439c5b | ||
|
|
05f7631023 | ||
|
|
2050902767 | ||
|
|
7c97dcd985 |
@@ -80,11 +80,9 @@ usb:v1C7Ap0571*
|
||||
# Supported by libfprint driver egismoc
|
||||
usb:v1C7Ap0582*
|
||||
usb:v1C7Ap0583*
|
||||
usb:v1C7Ap0584*
|
||||
usb:v1C7Ap0586*
|
||||
usb:v1C7Ap0587*
|
||||
usb:v1C7Ap05A1*
|
||||
usb:v1C7Ap05A5*
|
||||
ID_AUTOSUSPEND=1
|
||||
ID_PERSIST=0
|
||||
|
||||
@@ -430,6 +428,7 @@ usb:v16D1p1027*
|
||||
usb:v1C7Ap0300*
|
||||
usb:v1C7Ap0575*
|
||||
usb:v1C7Ap0576*
|
||||
usb:v1C7Ap0584*
|
||||
usb:v1C7Ap0577*
|
||||
usb:v1C7Ap057E*
|
||||
usb:v2541p0236*
|
||||
|
||||
@@ -40,6 +40,8 @@ fp_device_has_feature
|
||||
fp_device_has_storage
|
||||
fp_device_supports_identify
|
||||
fp_device_supports_capture
|
||||
fp_device_get_persistent_data
|
||||
fp_device_set_persistent_data
|
||||
fp_device_is_open
|
||||
fp_device_open
|
||||
fp_device_close
|
||||
@@ -100,12 +102,6 @@ FP_TYPE_IMAGE_DEVICE
|
||||
FpImageDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-sdcp-device</FILE>
|
||||
FP_TYPE_SDCP_DEVICE
|
||||
FpSdcpDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-print</FILE>
|
||||
FP_TYPE_PRINT
|
||||
@@ -221,31 +217,6 @@ fpi_image_device_retry_scan
|
||||
fpi_image_device_set_bz3_threshold
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-sdcp-device</FILE>
|
||||
<TITLE>Internal FpSdcpDevice</TITLE>
|
||||
FpiSdcpClaim
|
||||
FpSdcpDeviceClass
|
||||
fpi_sdcp_claim_get_type
|
||||
fpi_sdcp_claim_new
|
||||
fpi_sdcp_claim_copy
|
||||
fpi_sdcp_claim_free
|
||||
fpi_sdcp_device_open_complete
|
||||
fpi_sdcp_device_get_connect_data
|
||||
fpi_sdcp_device_connect_complete
|
||||
fpi_sdcp_device_get_reconnect_data
|
||||
fpi_sdcp_device_reconnect_complete
|
||||
fpi_sdcp_device_list_complete
|
||||
fpi_sdcp_device_enroll_commit
|
||||
fpi_sdcp_device_enroll_commit_complete
|
||||
fpi_sdcp_device_get_identify_data
|
||||
fpi_sdcp_device_set_identify_data
|
||||
fpi_sdcp_device_identify_retry
|
||||
fpi_sdcp_device_identify_complete
|
||||
fpi_sdcp_device_get_print_id
|
||||
fpi_sdcp_device_set_print_id
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fpi-log</FILE>
|
||||
fp_dbg
|
||||
@@ -254,8 +225,6 @@ fp_warn
|
||||
fp_err
|
||||
BUG_ON
|
||||
BUG
|
||||
fp_dbg_hex_dump_bytes
|
||||
fp_dbg_hex_dump_gbytes
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
<xi:include href="xml/fp-context.xml"/>
|
||||
<xi:include href="xml/fp-device.xml"/>
|
||||
<xi:include href="xml/fp-image-device.xml"/>
|
||||
<xi:include href="xml/fp-sdcp-device.xml"/>
|
||||
<xi:include href="xml/fp-print.xml"/>
|
||||
<xi:include href="xml/fp-image.xml"/>
|
||||
</part>
|
||||
@@ -39,7 +38,6 @@
|
||||
<title>Device methods for drivers</title>
|
||||
<xi:include href="xml/fpi-device.xml"/>
|
||||
<xi:include href="xml/fpi-image-device.xml"/>
|
||||
<xi:include href="xml/fpi-sdcp-device.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-helpers">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,10 +18,13 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "drivers_api.h"
|
||||
|
||||
#ifndef __EGIS0570_H
|
||||
|
||||
#define __EGIS0570_H 1
|
||||
|
||||
|
||||
/*
|
||||
* Device data
|
||||
*/
|
||||
@@ -54,6 +57,33 @@
|
||||
|
||||
#define EGIS0570_INIT_TOTAL (sizeof ((init_pkts)) / sizeof ((init_pkts[0])))
|
||||
|
||||
// static unsigned char init_pkts[][EGIS0570_PKTSIZE] =
|
||||
// {
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x58, 0x3f },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x21, 0x09 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x57, 0x09 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x22, 0x03 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x56, 0x03 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x23, 0x01 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x01 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x01 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x01 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3e },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0b },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x03 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x80 },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f },
|
||||
// { 0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0xfe } /* image returned after this packet */
|
||||
// };
|
||||
|
||||
static unsigned char init_pkts[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x20, 0x3f },
|
||||
@@ -66,6 +96,8 @@ static unsigned char init_pkts[][EGIS0570_PKTSIZE] =
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x55, 0x01 },
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x24, 0x01 },
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x54, 0x01 },
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x25, 0x00 },
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x53, 0x00 },
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3e },
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0b },
|
||||
{ 0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x03 },
|
||||
@@ -175,3 +207,386 @@ static unsigned char repeat_pkts[][EGIS0570_PKTSIZE] =
|
||||
#define EGIS0570_RESIZE 2
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// Calibration
|
||||
|
||||
enum driver_version {
|
||||
PACKET_CALIBRATION,
|
||||
PACKET_VERSION_1,
|
||||
NONE,
|
||||
};
|
||||
|
||||
#define PRESISTENT_DATA_LENGTH 9
|
||||
#define EGIS0570_CAL_IMG_TOT 22 //124
|
||||
#define EGIS0570_CAL_INPSIZE 6528
|
||||
#define EGIS0570_CAL_BS_ELM 7
|
||||
|
||||
|
||||
#define IMG_COL_IGNORE 23
|
||||
#define TARGET_UPPER 80
|
||||
#define TARGET_LOWER 70
|
||||
// #define SIDE_DIFF (-10)
|
||||
#define SIDE_DIFF (+5)
|
||||
|
||||
/* static pkts */
|
||||
static guint8 EGIS0570_CAL_CONFIGURATION_MODE_PKT[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0d, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0e, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x1f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x05, 0x08},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0xff}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_PKT_ZERO_RANGE[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x01, 0x10},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x04, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x05, 0x08},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x06, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x07, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x08, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0a, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0b, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0c, 0xff},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0d, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0e, 0x00}
|
||||
};
|
||||
|
||||
|
||||
static guint8 EGIS0570_CAL_CAPTURING_AREA[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x38},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x71}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_SENSOR_AND_EMITTER[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x15},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x08}
|
||||
};
|
||||
|
||||
|
||||
static guint8 EGIS0570_CAL_WHITE_SETTING[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x3f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x00}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_BLACK_WHITE_GET_IMAGE[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x20},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0x33}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_BLACK_WHITE_AFTER_IMAGE[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x00}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_BLACK_SETTING[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x03},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0xff},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0xff}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_BLACK_WHITE_CLEAR[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x03, 0x80},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00}
|
||||
};
|
||||
|
||||
|
||||
static guint8 EGIS0570_CAL_MIDDLE_BLACK_SETTING[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x7f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x7f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_GET_IMAGE[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x06, 0x00, 0x33}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_AFTER_IMAGE[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x0f}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_REPEAT[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x0f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_BORDER_WHITE_SETTING[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x0a},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x3f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x02, 0x3f},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f}
|
||||
};
|
||||
|
||||
|
||||
static guint8 EGIS0570_CAL_FIRST_BS_SETTING[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00},
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_BEFORE_GET_IMAGE[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x2f}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_NO_IMAGE_CAPTURING_AREA[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x10, 0x1c},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x11, 0x1c},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x12, 0x31},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x13, 0x40}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_NO_IMAGE_SETTING_0[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x09, 0x05},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x14, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x15, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x16, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x08, 0x1c}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_NO_IMAGE_BINARY_14_SETTING[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0b, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0c, 0xff},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0d, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x0e, 0xff},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x02, 0x1d},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x04, 0x00}
|
||||
};
|
||||
|
||||
static guint8 EGIS0570_CAL_NO_IMAGE_PRE_FIRST[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x01, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x01, 0x00}
|
||||
};
|
||||
|
||||
|
||||
static guint8 EGIS0570_CAL_NO_IMAGE_REQUEST[][EGIS0570_PKTSIZE] =
|
||||
{
|
||||
{0x45, 0x47, 0x49, 0x53, 0x01, 0x01, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x01, 0x00},
|
||||
{0x45, 0x47, 0x49, 0x53, 0x00, 0x01, 0x00}
|
||||
};
|
||||
|
||||
|
||||
#define EGIS0570_CAL_STATIC_LIST_SIZEOF (sizeof ((EGIS0570_CAL_STATIC_LIST)) / sizeof ((EGIS0570_CAL_STATIC_LIST[0])))
|
||||
|
||||
static guint8 * EGIS0570_CAL_STATIC_LIST[] = {
|
||||
*EGIS0570_CAL_CONFIGURATION_MODE_PKT,
|
||||
*EGIS0570_CAL_PKT_ZERO_RANGE,
|
||||
*EGIS0570_CAL_CAPTURING_AREA,
|
||||
*EGIS0570_CAL_SENSOR_AND_EMITTER,
|
||||
*EGIS0570_CAL_WHITE_SETTING,
|
||||
*EGIS0570_CAL_BLACK_WHITE_GET_IMAGE,
|
||||
*EGIS0570_CAL_BLACK_WHITE_AFTER_IMAGE,
|
||||
*EGIS0570_CAL_BLACK_SETTING,
|
||||
*EGIS0570_CAL_BLACK_WHITE_CLEAR,
|
||||
*EGIS0570_CAL_MIDDLE_BLACK_SETTING,
|
||||
*EGIS0570_CAL_GET_IMAGE,
|
||||
*EGIS0570_CAL_AFTER_IMAGE,
|
||||
*EGIS0570_CAL_REPEAT,
|
||||
*EGIS0570_CAL_BORDER_WHITE_SETTING,
|
||||
*EGIS0570_CAL_FIRST_BS_SETTING,
|
||||
*EGIS0570_CAL_BEFORE_GET_IMAGE,
|
||||
*EGIS0570_CAL_NO_IMAGE_CAPTURING_AREA,
|
||||
*EGIS0570_CAL_NO_IMAGE_SETTING_0,
|
||||
*EGIS0570_CAL_NO_IMAGE_BINARY_14_SETTING,
|
||||
*EGIS0570_CAL_NO_IMAGE_PRE_FIRST,
|
||||
*EGIS0570_CAL_NO_IMAGE_REQUEST,
|
||||
};
|
||||
|
||||
|
||||
#define EGIS0570_HELPER_PKT_SIZEOF(x) (sizeof (x) / sizeof (x[0]))
|
||||
|
||||
static guint8 EGIS0570_CAL_STATIC_LIST_SIZE[] = {
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_CONFIGURATION_MODE_PKT),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_PKT_ZERO_RANGE),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_CAPTURING_AREA),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_SENSOR_AND_EMITTER),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_WHITE_SETTING),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BLACK_WHITE_GET_IMAGE),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BLACK_WHITE_AFTER_IMAGE),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BLACK_SETTING),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BLACK_WHITE_CLEAR),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_MIDDLE_BLACK_SETTING),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_GET_IMAGE),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_AFTER_IMAGE),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_REPEAT),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BORDER_WHITE_SETTING),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_FIRST_BS_SETTING),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_BEFORE_GET_IMAGE),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_CAPTURING_AREA),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_SETTING_0),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_BINARY_14_SETTING),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_PRE_FIRST),
|
||||
EGIS0570_HELPER_PKT_SIZEOF (EGIS0570_CAL_NO_IMAGE_REQUEST),
|
||||
};
|
||||
|
||||
|
||||
/* Calibration logic */
|
||||
enum cal_proc_en {
|
||||
CAL_CONF_PKT,
|
||||
CAL_PKT_ZERO_RNG,
|
||||
CAL_CAPT_AREA,
|
||||
CAL_SENS_AND_EMIT,
|
||||
CAL_RNG_20_58,
|
||||
CAL_RNG_60_D0,
|
||||
CAL_WHITE_SET,
|
||||
CAL_BLACK_WHITE_GET_IMG,
|
||||
CAL_BLACK_WHITE_AFTER_IMAGE,
|
||||
CAL_BLACK_SET,
|
||||
CAL_CHECK_BLACK_WHITE,
|
||||
CAL_5_ROWS_ZEROS,
|
||||
CAL_BLACK_WHITE_CLEAR,
|
||||
CAL_RNG_60_D1,
|
||||
CAL_MID_BLACK_SET,
|
||||
CAL_GET_IMG,
|
||||
CAL_AFTER_IMG,
|
||||
CAL_GET_9,
|
||||
CAL_BORDER_WHITE_SET,
|
||||
CAL_FIRST_BS_SET,
|
||||
CAL_BS_CHK_SET,
|
||||
CAL_PKT_02,
|
||||
CAL_BEFORE_IMG,
|
||||
CAL_BS_JUMP,
|
||||
CAL_BS_END,
|
||||
CAL_PKT_15_0,
|
||||
CAL_PKT_16_3C,
|
||||
CAL_CHK_NEW_CONF,
|
||||
CAL_GET_21,
|
||||
CAL_NO_IMG_CAP_AREA,
|
||||
CAL_NO_IMG_SET_0,
|
||||
CAL_NO_IMG_03_1C,
|
||||
CAL_NO_CHK_03_80,
|
||||
CAL_NO_SET_03_80,
|
||||
CAL_NO_IMG_14_BS_SET,
|
||||
CAL_NO_IMG_14_BS_CHK_SET,
|
||||
CAL_NO_IMG_PRE_FIRST,
|
||||
CAL_NO_IMG_GET_8,
|
||||
CAL_NO_IMG_14_BS_JUMP,
|
||||
CAL_NO_IMG_14_BS_END,
|
||||
CAL_NO_IMG_16_BS_SET,
|
||||
CAL_NO_IMG_16_BS_CHK_SET_15,
|
||||
CAL_NO_IMG_16_BS_SET_16,
|
||||
CAL_NO_IMG_16_BS_JUMP,
|
||||
CAL_NO_IMG_16_BS_END,
|
||||
|
||||
|
||||
CAL_END,
|
||||
};
|
||||
|
||||
|
||||
#define EGIS0570_CAL_PROC_SIZEOF (sizeof ((calibration_procedure)) / sizeof ((calibration_procedure[0])))
|
||||
|
||||
static guint8 calibration_procedure[] = {
|
||||
// conf
|
||||
CAL_CONF_PKT,
|
||||
// sensor check
|
||||
CAL_PKT_ZERO_RNG,
|
||||
CAL_CAPT_AREA,
|
||||
CAL_SENS_AND_EMIT,
|
||||
CAL_RNG_20_58,
|
||||
CAL_RNG_60_D0,
|
||||
CAL_WHITE_SET,
|
||||
CAL_BLACK_WHITE_GET_IMG,
|
||||
CAL_BLACK_WHITE_AFTER_IMAGE,
|
||||
CAL_BLACK_SET,
|
||||
CAL_BLACK_WHITE_GET_IMG,
|
||||
CAL_BLACK_WHITE_AFTER_IMAGE,
|
||||
CAL_CHECK_BLACK_WHITE,
|
||||
// not binary 16
|
||||
CAL_CAPT_AREA,
|
||||
CAL_5_ROWS_ZEROS,
|
||||
CAL_BLACK_WHITE_CLEAR,
|
||||
CAL_RNG_20_58,
|
||||
CAL_RNG_60_D1,
|
||||
CAL_MID_BLACK_SET,
|
||||
CAL_GET_IMG,
|
||||
CAL_AFTER_IMG,
|
||||
CAL_GET_9,
|
||||
CAL_BORDER_WHITE_SET,
|
||||
CAL_GET_IMG,
|
||||
CAL_AFTER_IMG,
|
||||
CAL_GET_9,
|
||||
// binary
|
||||
CAL_FIRST_BS_SET,
|
||||
CAL_BS_CHK_SET, // 0
|
||||
CAL_PKT_02, // 1
|
||||
CAL_BEFORE_IMG, // 2
|
||||
CAL_GET_IMG, // 3
|
||||
CAL_AFTER_IMG, // 4
|
||||
CAL_GET_9, // 5
|
||||
CAL_BS_JUMP, // 6
|
||||
CAL_BS_END, // 7
|
||||
// check pictures.
|
||||
CAL_PKT_15_0,
|
||||
CAL_PKT_16_3C,
|
||||
CAL_CHK_NEW_CONF,
|
||||
CAL_PKT_02,
|
||||
CAL_BEFORE_IMG,
|
||||
CAL_GET_IMG,
|
||||
CAL_AFTER_IMG,
|
||||
CAL_GET_21,
|
||||
// no image 14
|
||||
CAL_NO_IMG_CAP_AREA,
|
||||
CAL_NO_IMG_SET_0,
|
||||
CAL_NO_IMG_03_1C,
|
||||
CAL_NO_CHK_03_80,
|
||||
CAL_NO_SET_03_80,
|
||||
CAL_NO_IMG_14_BS_SET,
|
||||
CAL_NO_IMG_14_BS_CHK_SET, // 0
|
||||
CAL_NO_IMG_PRE_FIRST, // 1
|
||||
CAL_NO_IMG_GET_8, // 2
|
||||
CAL_NO_IMG_14_BS_JUMP, // 3
|
||||
CAL_NO_IMG_14_BS_END, // 4
|
||||
// no image 16
|
||||
CAL_NO_IMG_16_BS_SET,
|
||||
CAL_NO_IMG_16_BS_CHK_SET_15, // 0
|
||||
CAL_NO_IMG_16_BS_SET_16, // 1
|
||||
CAL_NO_IMG_PRE_FIRST, // 2
|
||||
CAL_NO_IMG_GET_8, // 3
|
||||
CAL_NO_IMG_16_BS_JUMP, // 4
|
||||
CAL_NO_IMG_16_BS_END, // 5
|
||||
// end
|
||||
CAL_CONF_PKT,
|
||||
CAL_CONF_PKT,
|
||||
|
||||
CAL_END,
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,15 @@
|
||||
/*
|
||||
* Driver for Egis Technology (LighTuning) Match-On-Chip sensors
|
||||
* Copyright (C) 2023-2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
* Originally authored 2023 by Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* Portions of code and logic inspired from the elanmoc libfprint driver
|
||||
* which is copyright (C) 2021 Elan Microelectronics Inc (see elanmoc.c)
|
||||
*
|
||||
* Based on original reverse-engineering work by Joshua Grisham. The protocol has
|
||||
* been reverse-engineered from captures of the official Windows driver, and by
|
||||
* testing commands on the sensor with a multiplatform Python prototype driver:
|
||||
* https://github.com/joshuagrisham/galaxy-book2-pro-linux/tree/main/fingerprint/
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
@@ -22,18 +27,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-device.h"
|
||||
#include "fpi-ssm.h"
|
||||
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC, FpSdcpDevice)
|
||||
G_DECLARE_FINAL_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC, FpDevice)
|
||||
|
||||
#define EGISMOC_DRIVER_FULLNAME "Egis Technology (LighTuning) Match-on-Chip"
|
||||
|
||||
#define EGISMOC_DRIVER_CHECK_PREFIX_TYPE1 (1 << 0)
|
||||
#define EGISMOC_DRIVER_CHECK_PREFIX_TYPE2 (1 << 1)
|
||||
#define EGISMOC_DRIVER_MAX_ENROLL_STAGES_20 (1 << 2)
|
||||
#define EGISMOC_DRIVER_MAX_ENROLL_STAGES_15 (1 << 3)
|
||||
|
||||
#define EGISMOC_EP_CMD_OUT (0x02 | FPI_USB_ENDPOINT_OUT)
|
||||
#define EGISMOC_EP_CMD_IN (0x81 | FPI_USB_ENDPOINT_IN)
|
||||
@@ -49,11 +52,7 @@ G_DECLARE_FINAL_TYPE (FpiDeviceEgisMoc, fpi_device_egismoc, FPI, DEVICE_EGISMOC,
|
||||
|
||||
#define EGISMOC_MAX_ENROLL_STAGES_DEFAULT 10
|
||||
#define EGISMOC_MAX_ENROLL_NUM 10
|
||||
#define EGISMOC_FINGER_ON_SENSOR_TIMEOUT_USEC (10 * G_USEC_PER_SEC)
|
||||
|
||||
#define EGISMOC_CONNECT_RESPONSE_PREFIX_SIZE 15
|
||||
#define EGISMOC_IDENTIFY_RESPONSE_PREFIX_SIZE 14
|
||||
#define EGISMOC_ENROLL_STARTING_RESPONSE_PREFIX_SIZE 14
|
||||
#define EGISMOC_FINGERPRINT_DATA_SIZE 32
|
||||
#define EGISMOC_LIST_RESPONSE_PREFIX_SIZE 14
|
||||
#define EGISMOC_LIST_RESPONSE_SUFFIX_SIZE 2
|
||||
|
||||
@@ -73,9 +72,6 @@ static gsize cmd_fw_version_len = sizeof (cmd_fw_version) / sizeof (cmd_fw_versi
|
||||
static guchar rsp_fw_version_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_fw_version_suffix_len = sizeof (rsp_fw_version_suffix) / sizeof (rsp_fw_version_suffix[0]);
|
||||
|
||||
static guchar rsp_sensor_has_finger_suffix[] = {0x90, 0x00, 0x90, 0x00};
|
||||
static gsize rsp_sensor_has_finger_suffix_len = sizeof (rsp_sensor_has_finger_suffix) / sizeof (rsp_sensor_has_finger_suffix[0]);
|
||||
|
||||
static guchar cmd_list[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x19, 0x04, 0x00, 0x00, 0x01, 0x40};
|
||||
static gsize cmd_list_len = sizeof (cmd_list) / sizeof (cmd_list[0]);
|
||||
|
||||
@@ -97,19 +93,18 @@ static gsize cmd_sensor_enroll_len = sizeof (cmd_sensor_enroll) / sizeof (cmd_se
|
||||
|
||||
static guchar cmd_enroll_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x01, 0x00, 0x00, 0x00, 0x20};
|
||||
static gsize cmd_enroll_starting_len = sizeof (cmd_enroll_starting) / sizeof (cmd_enroll_starting[0]);
|
||||
static guchar rsp_enroll_starting_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_enroll_starting_suffix_len = sizeof (rsp_enroll_starting_suffix) / sizeof (rsp_enroll_starting_suffix[0]);
|
||||
|
||||
static guchar cmd_sensor_start_capture[] = {0x00, 0x00, 0x00, 0x04, 0x50, 0x16, 0x02, 0x01};
|
||||
static gsize cmd_sensor_start_capture_len = sizeof (cmd_sensor_start_capture) / sizeof (cmd_sensor_start_capture[0]);
|
||||
|
||||
static guchar cmd_capture_post_wait_finger[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x80};
|
||||
static gsize cmd_capture_post_wait_finger_len = sizeof (cmd_capture_post_wait_finger) / sizeof (cmd_capture_post_wait_finger[0]);
|
||||
|
||||
static guchar cmd_read_capture[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x02, 0x02, 0x00, 0x00, 0x02};
|
||||
static gsize cmd_read_capture_len = sizeof (cmd_read_capture) / sizeof (cmd_read_capture[0]);
|
||||
static guchar rsp_read_success_prefix[] = {0x00, 0x00, 0x00, 0x04};
|
||||
static gsize rsp_read_success_prefix_len = sizeof (rsp_read_success_prefix) / sizeof (rsp_read_success_prefix[0]);
|
||||
static guchar rsp_read_success_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_read_success_suffix_len = sizeof (rsp_read_success_suffix) / sizeof (rsp_read_success_suffix[0]);
|
||||
static guchar rsp_read_offcenter_prefix[] = {0x00, 0x00, 0x00, 0x04};
|
||||
static gsize rsp_read_offcenter_prefix_len = sizeof (rsp_read_offcenter_prefix) / sizeof (rsp_read_offcenter_prefix[0]);
|
||||
static guchar rsp_read_offcenter_suffix[] = {0x64, 0x91};
|
||||
static gsize rsp_read_offcenter_suffix_len = sizeof (rsp_read_offcenter_suffix) / sizeof (rsp_read_offcenter_suffix[0]);
|
||||
static guchar rsp_read_dirty_prefix[] = {0x00, 0x00, 0x00, 0x02, 0x64};
|
||||
@@ -117,8 +112,6 @@ static gsize rsp_read_dirty_prefix_len = sizeof (rsp_read_dirty_prefix) / sizeof
|
||||
|
||||
static guchar cmd_commit_starting[] = {0x00, 0x00, 0x00, 0x07, 0x50, 0x16, 0x05, 0x00, 0x00, 0x00, 0x20};
|
||||
static gsize cmd_commit_starting_len = sizeof (cmd_commit_starting) / sizeof (cmd_commit_starting[0]);
|
||||
static guchar rsp_commit_success_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_commit_success_suffix_len = sizeof (rsp_commit_success_suffix) / sizeof (rsp_commit_success_suffix[0]);
|
||||
|
||||
|
||||
/* commands which exist on the device but are currently not used */
|
||||
@@ -137,13 +130,8 @@ static gsize rsp_commit_success_suffix_len = sizeof (rsp_commit_success_suffix)
|
||||
/* prefixes/suffixes and other things for dynamically created command payloads */
|
||||
|
||||
#define EGISMOC_CHECK_BYTES_LENGTH 2
|
||||
|
||||
static guchar cmd_sdcp_connect_prefix[] = {0x00, 0x00, 0x00, 0x6b, 0x50, 0x57, 0x01, 0x00, 0x00, 0x00, 0x62, 0x20};
|
||||
static gsize cmd_sdcp_connect_prefix_len = sizeof (cmd_sdcp_connect_prefix) / sizeof (cmd_sdcp_connect_prefix[0]);
|
||||
static guchar cmd_sdcp_connect_suffix[] = {0x00, 0x00};
|
||||
static gsize cmd_sdcp_connect_suffix_len = sizeof (cmd_sdcp_connect_suffix) / sizeof (cmd_sdcp_connect_suffix[0]);
|
||||
static guchar rsp_sdcp_connect_success_suffix[] = {0x90, 0x00};
|
||||
static gsize rsp_sdcp_connect_success_suffix_len = sizeof (rsp_sdcp_connect_success_suffix) / sizeof (rsp_sdcp_connect_success_suffix[0]);
|
||||
#define EGISMOC_IDENTIFY_RESPONSE_PRINT_ID_OFFSET 46
|
||||
#define EGISMOC_CMD_CHECK_SEPARATOR_LENGTH 32
|
||||
|
||||
static guchar cmd_new_print_prefix[] = {0x00, 0x00, 0x00, 0x27, 0x50, 0x16, 0x03, 0x00, 0x00, 0x00, 0x20};
|
||||
static gsize cmd_new_print_prefix_len = sizeof (cmd_new_print_prefix) / sizeof (cmd_new_print_prefix[0]);
|
||||
@@ -181,18 +169,6 @@ typedef enum {
|
||||
DEV_INIT_STATES,
|
||||
} DeviceInitStates;
|
||||
|
||||
typedef enum {
|
||||
CONNECT,
|
||||
CONNECT_RESPONSE,
|
||||
CONNECT_STATES,
|
||||
} ConnectStates;
|
||||
|
||||
typedef enum {
|
||||
WAIT_FINGER_NOT_ON_SENSOR,
|
||||
WAIT_FINGER_ON_SENSOR,
|
||||
WAIT_FINGER_STATES,
|
||||
} WaitFingerStates;
|
||||
|
||||
typedef enum {
|
||||
IDENTIFY_GET_ENROLLED_IDS,
|
||||
IDENTIFY_CHECK_ENROLLED_NUM,
|
||||
@@ -201,6 +177,8 @@ typedef enum {
|
||||
IDENTIFY_WAIT_FINGER,
|
||||
IDENTIFY_SENSOR_CHECK,
|
||||
IDENTIFY_CHECK,
|
||||
IDENTIFY_COMPLETE_SENSOR_RESET,
|
||||
IDENTIFY_COMPLETE,
|
||||
IDENTIFY_STATES,
|
||||
} IdentifyStates;
|
||||
|
||||
@@ -216,10 +194,11 @@ typedef enum {
|
||||
ENROLL_CAPTURE_SENSOR_RESET,
|
||||
ENROLL_CAPTURE_SENSOR_START_CAPTURE,
|
||||
ENROLL_CAPTURE_WAIT_FINGER,
|
||||
ENROLL_CAPTURE_POST_WAIT_FINGER,
|
||||
ENROLL_CAPTURE_READ_RESPONSE,
|
||||
ENROLL_COMMIT_START,
|
||||
ENROLL_COMMIT,
|
||||
ENROLL_COMMIT_SENSOR_RESET,
|
||||
ENROLL_COMPLETE,
|
||||
ENROLL_STATES,
|
||||
} EnrollStates;
|
||||
|
||||
|
||||
@@ -1,331 +0,0 @@
|
||||
/*
|
||||
* Virtual driver for SDCP device debugging
|
||||
*
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
/*
|
||||
* This is a virtual driver to debug the SDCP-based drivers.
|
||||
* This virtual driver does not use a socket listener but instead
|
||||
* embeds the simulated logic of the fake "device" directly within
|
||||
* the logic of each function. This driver also allows prints to be
|
||||
* registered programmatically, making it possible to test libfprint
|
||||
* and fprintd.
|
||||
*
|
||||
* This virtual driver will override FpSdcpDevice's dynamically
|
||||
* generated cryptography values and instead replace them with
|
||||
* pre-generated values taken from from Microsoft's sample client
|
||||
* implementation. See:
|
||||
* https://github.com/Microsoft/SecureDeviceConnectionProtocol
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "virtual_sdcp"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "../fpi-sdcp.h"
|
||||
#include "virtual-sdcp.h"
|
||||
|
||||
struct _FpDeviceVirtualSdcp
|
||||
{
|
||||
FpSdcpDevice parent;
|
||||
|
||||
GPtrArray *print_ids;
|
||||
};
|
||||
|
||||
G_DECLARE_FINAL_TYPE (FpDeviceVirtualSdcp, fpi_device_virtual_sdcp, FPI, DEVICE_VIRTUAL_SDCP, FpSdcpDevice)
|
||||
G_DEFINE_TYPE (FpDeviceVirtualSdcp, fpi_device_virtual_sdcp, FP_TYPE_SDCP_DEVICE)
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static const guint8 from_hex_map[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
|
||||
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
|
||||
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // @abcdef
|
||||
};
|
||||
|
||||
static GBytes *
|
||||
g_bytes_from_hex (const gchar *hex)
|
||||
{
|
||||
g_autoptr(GBytes) res = NULL;
|
||||
guint8 b0, b1;
|
||||
gsize bytes_len = strlen (hex) / 2;
|
||||
guint8 *bytes = g_malloc0 (bytes_len);
|
||||
|
||||
for (int i = 0; i < strlen (hex) - 1; i += 2)
|
||||
{
|
||||
b0 = ((guint8) hex[i + 0] & 0x1F) ^ 0x10;
|
||||
b1 = ((guint8) hex[i + 1] & 0x1F) ^ 0x10;
|
||||
bytes[i / 2] = (guint8) (from_hex_map[b0] << 4) | from_hex_map[b1];
|
||||
}
|
||||
|
||||
res = g_bytes_new_take (bytes, bytes_len);
|
||||
|
||||
return g_steal_pointer (&res);
|
||||
}
|
||||
|
||||
static FpiSdcpClaim *
|
||||
get_fake_sdcp_claim (void)
|
||||
{
|
||||
FpiSdcpClaim *claim = g_new0 (FpiSdcpClaim, 1);
|
||||
|
||||
claim->model_certificate = g_bytes_from_hex (model_certificate_hex);
|
||||
claim->device_public_key = g_bytes_from_hex (device_public_key_hex);
|
||||
claim->firmware_public_key = g_bytes_from_hex (firmware_public_key_hex);
|
||||
claim->firmware_hash = g_bytes_from_hex (firmware_hash_hex);
|
||||
claim->model_signature = g_bytes_from_hex (model_signature_hex);
|
||||
claim->device_signature = g_bytes_from_hex (device_signature_hex);
|
||||
return g_steal_pointer (&claim);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void
|
||||
dev_identify (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (sdcp_device);
|
||||
g_autoptr(GBytes) enrollment_id = NULL;
|
||||
g_autoptr(GBytes) identify_mac = NULL;
|
||||
GBytes *identify_nonce = NULL;
|
||||
|
||||
if (self->print_ids->len > 0)
|
||||
{
|
||||
/*
|
||||
* Pretend that the virtual device identified the first print.
|
||||
* Since we used a pre-generated enrollment_id for it, we can also use the
|
||||
* matching pre-generated test identify data for its identification.
|
||||
*/
|
||||
identify_nonce = g_bytes_from_hex (identify_nonce_hex);
|
||||
enrollment_id = g_bytes_from_hex (enrollment_id_hex);
|
||||
fpi_sdcp_device_set_identify_data (sdcp_device, identify_nonce);
|
||||
identify_mac = g_bytes_from_hex (identify_mac_hex);
|
||||
|
||||
fpi_sdcp_device_identify_complete (sdcp_device, enrollment_id, identify_mac, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_sdcp_device_identify_complete (sdcp_device, NULL, NULL,
|
||||
fpi_device_error_new (FP_DEVICE_ERROR_DATA_NOT_FOUND));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dev_enroll_commit (FpSdcpDevice *sdcp_device, GBytes *id)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (sdcp_device);
|
||||
g_autoptr(GBytes) expected_first_print_id = NULL;
|
||||
GBytes *print_id;
|
||||
|
||||
print_id = g_bytes_new (g_bytes_get_data (id, NULL), g_bytes_get_size (id));
|
||||
|
||||
/*
|
||||
* If this is the first print, it is probably good if we make sure the
|
||||
* internal API assigned it the expected pre-known ID
|
||||
*/
|
||||
if (self->print_ids->len == 0)
|
||||
{
|
||||
expected_first_print_id = g_bytes_from_hex (enrollment_id_hex);
|
||||
if (!g_bytes_equal (print_id, expected_first_print_id))
|
||||
{
|
||||
fpi_sdcp_device_enroll_commit_complete (sdcp_device,
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_UNTRUSTED,
|
||||
"First enrolled print ID does not match expected value"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
g_ptr_array_add (self->print_ids, g_steal_pointer (&print_id));
|
||||
|
||||
fpi_sdcp_device_enroll_commit_complete (sdcp_device, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_enroll (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (sdcp_device);
|
||||
FpDevice *device = FP_DEVICE (sdcp_device);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) nonce = NULL;
|
||||
FpPrint *print;
|
||||
|
||||
fpi_device_get_enroll_data (device, &print);
|
||||
|
||||
if (self->print_ids->len == 0)
|
||||
{
|
||||
/* Use the hard-coded nonce for the first enrollment */
|
||||
nonce = g_bytes_from_hex (enrollment_nonce_hex);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Generate a new nonce for all other enrollments */
|
||||
nonce = fpi_sdcp_generate_random (&error);
|
||||
if (error)
|
||||
fpi_device_enroll_progress (device, 0, print, error);
|
||||
}
|
||||
|
||||
fpi_device_enroll_progress (device, 1, print, NULL);
|
||||
fpi_sdcp_device_enroll_commit (sdcp_device, nonce, error);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_list (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (sdcp_device);
|
||||
GPtrArray *print_ids = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
|
||||
|
||||
for (gint i = 0; i < self->print_ids->len; i++)
|
||||
{
|
||||
GBytes *print_id = g_ptr_array_index (self->print_ids, i);
|
||||
fp_dbg ("print %d:", i);
|
||||
fp_dbg_hex_dump_gbytes (print_id);
|
||||
g_ptr_array_add (print_ids, g_bytes_new (g_bytes_get_data (print_id, NULL),
|
||||
g_bytes_get_size (print_id)));
|
||||
}
|
||||
|
||||
fpi_sdcp_device_list_complete (sdcp_device, g_steal_pointer (&print_ids), NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_reconnect (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) random = NULL;
|
||||
g_autoptr(GBytes) reconnect_mac = g_bytes_from_hex (reconnect_mac_hex);
|
||||
|
||||
/*
|
||||
* Normally, a driver would fetch the reconnect data and then send it to the
|
||||
* device's Reconnect command. In this fake device, we will just fetch and
|
||||
* verify the random was generated but do nothing with it
|
||||
*/
|
||||
|
||||
fpi_sdcp_device_get_reconnect_data (sdcp_device, &random);
|
||||
|
||||
g_assert (random);
|
||||
g_assert (g_bytes_get_size (random) == SDCP_RANDOM_SIZE);
|
||||
|
||||
/*
|
||||
* In emulation mode (FP_DEVICE_EMULATION=1), a different hard-coded random is
|
||||
* set in fpi-sdcp-device, which was the same random used to generate the
|
||||
* reconnect_mac value provided here
|
||||
*/
|
||||
|
||||
fpi_sdcp_device_reconnect_complete (sdcp_device, reconnect_mac, error);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_connect (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) host_random = NULL;
|
||||
g_autoptr(GBytes) host_public_key = NULL;
|
||||
g_autoptr(GBytes) device_random = g_bytes_from_hex (device_random_hex);
|
||||
g_autoptr(GBytes) connect_mac = g_bytes_from_hex (connect_mac_hex);
|
||||
g_autoptr(FpiSdcpClaim) claim = get_fake_sdcp_claim ();
|
||||
|
||||
fpi_sdcp_device_get_connect_data (sdcp_device, &host_random, &host_public_key);
|
||||
|
||||
g_assert (host_random);
|
||||
g_assert (g_bytes_get_size (host_random) == SDCP_RANDOM_SIZE);
|
||||
|
||||
g_assert (host_public_key);
|
||||
g_assert (g_bytes_get_size (host_public_key) == SDCP_PUBLIC_KEY_SIZE);
|
||||
|
||||
fpi_sdcp_device_connect_complete (sdcp_device, device_random, claim, connect_mac, error);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_close (FpDevice *device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
fpi_device_close_complete (device, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
dev_open (FpSdcpDevice *sdcp_device)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
fpi_sdcp_device_open_complete (sdcp_device, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_finalize (GObject *object)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (object);
|
||||
|
||||
g_clear_pointer (&self->print_ids, g_ptr_array_unref);
|
||||
|
||||
G_OBJECT_CLASS (fpi_device_virtual_sdcp_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_init (FpDeviceVirtualSdcp *self)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
|
||||
/* Force FP_DEVICE_EMULATION=1 when using FpDeviceVirtualSdcp */
|
||||
g_setenv ("FP_DEVICE_EMULATION", "1", TRUE);
|
||||
|
||||
self->print_ids = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
|
||||
}
|
||||
|
||||
static const FpIdEntry driver_ids[] = {
|
||||
{ .virtual_envvar = "FP_VIRTUAL_SDCP" },
|
||||
{ .virtual_envvar = NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
fpi_device_virtual_sdcp_class_init (FpDeviceVirtualSdcpClass *klass)
|
||||
{
|
||||
fp_dbg ("Virtual SDCP device: %s()", G_STRFUNC);
|
||||
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
|
||||
FpSdcpDeviceClass *sdcp_dev_class = FP_SDCP_DEVICE_CLASS (klass);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->finalize = fpi_device_virtual_sdcp_finalize;
|
||||
|
||||
dev_class->id = FP_COMPONENT;
|
||||
dev_class->full_name = "Virtual SDCP device for debugging";
|
||||
dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
|
||||
dev_class->id_table = driver_ids;
|
||||
dev_class->nr_enroll_stages = 1;
|
||||
dev_class->scan_type = FP_SCAN_TYPE_PRESS;
|
||||
|
||||
sdcp_dev_class->ignore_device_certificate = FALSE;
|
||||
sdcp_dev_class->ignore_device_signatures = FALSE;
|
||||
|
||||
sdcp_dev_class->open = dev_open;
|
||||
sdcp_dev_class->connect = dev_connect;
|
||||
|
||||
if (!g_getenv ("FP_VIRTUAL_SDCP_NO_RECONNECT"))
|
||||
sdcp_dev_class->reconnect = dev_reconnect;
|
||||
|
||||
sdcp_dev_class->list = dev_list;
|
||||
sdcp_dev_class->enroll = dev_enroll;
|
||||
sdcp_dev_class->enroll_commit = dev_enroll_commit;
|
||||
sdcp_dev_class->identify = dev_identify;
|
||||
|
||||
dev_class->close = dev_close;
|
||||
|
||||
fpi_device_class_auto_initialize_features (dev_class);
|
||||
dev_class->features |= FP_DEVICE_FEATURE_STORAGE;
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* Virtual driver test payloads for SDCP device debugging
|
||||
*
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-compat.h"
|
||||
|
||||
/* host keys */
|
||||
|
||||
static const gchar host_private_key_hex[] = "8400ed14579cdf11586477e836e8cb52708441c1c2a447c218c5bbc2d118fbc7";
|
||||
static const gchar host_public_key_hex[] = "0452f056ffb9c6728654771a3629b770767b19a2106a4916fb81ba06ef6797c4"
|
||||
"a3df672ade0e9116d1abe278a8223abde4958d62d4ff6882159f0617c6f8ce10"
|
||||
"bf";
|
||||
static const gchar host_random_hex[] = "d877403abe82f4d97e1448c5052d83a532a45e56ef049cbbf981137520e713bf";
|
||||
|
||||
/* device keys */
|
||||
|
||||
static const gchar device_random_hex[] = "6e2f6c1abef2a1973fb1315a17e209fdb0c78520f1fd6a85d294d7aeb40a04a7";
|
||||
static const gchar model_certificate_hex[] = "30820323308202caa00302010202133300000004c45d661d6eed040d00000000"
|
||||
"0004300a06082a8648ce3d0403023056310b3009060355040613025553311e30"
|
||||
"1c060355040a13154d6963726f736f667420436f72706f726174696f6e312730"
|
||||
"250603550403131e57696e646f77732048656c6c6f2032303936414443432043"
|
||||
"412032303231301e170d3232303130343231303033355a170d32333034303432"
|
||||
"31303033355a301c311a3018060355040313115365637572652042494f205365"
|
||||
"6e736f723059301306072a8648ce3d020106082a8648ce3d0301070342000414"
|
||||
"cfc287f872a2b7d3339e0b31390e3ca688e61165eaa6687c959270e07666b1fa"
|
||||
"19e3efaf1750d134a886d494424fe471970c4b06838408a18d1f5d57735dd7a3"
|
||||
"8201af308201ab30750603551d11046e306ca46a30683132303006082b060104"
|
||||
"82376402132436423045413344382d383339372d343444332d383043392d3930"
|
||||
"324130414346344343303132303006082b060104823764011324413944423730"
|
||||
"32362d433646462d344341462d423134382d393133454641333730423933301d"
|
||||
"0603551d0e04160414db6d66d642b7236d5e6bb2ec2186decda98067b6301f06"
|
||||
"03551d23041830168014bf3748e34a632de953a3ba890298c069472a99b9305f"
|
||||
"0603551d1f045830563054a052a050864e687474703a2f2f7777772e6d696372"
|
||||
"6f736f66742e636f6d2f706b696f70732f63726c2f57696e646f777325323048"
|
||||
"656c6c6f25323032303936414443432532304341253230323032312e63726c30"
|
||||
"6c06082b060105050701010460305e305c06082b060105050730028650687474"
|
||||
"703a2f2f7777772e6d6963726f736f66742e636f6d2f706b696f70732f636572"
|
||||
"74732f57696e646f777325323048656c6c6f2532303230393641444343253230"
|
||||
"4341253230323032312e637274300c0603551d130101ff040230003015060355"
|
||||
"1d25040e300c060a2b0601040182374c2b01300a06082a8648ce3d0403020347"
|
||||
"003044022077553ef520f732e03cd740c8cf807e6366e12918bc581f75bfe0f1"
|
||||
"95b7b1fd4f0220324e25b93b9da7538b797a624272b21b7cc0e96ea487924250"
|
||||
"4677600450f283";
|
||||
static const gchar device_public_key_hex[] = "04e2787890a684f95b96b9a2316ca8d3d33d4d79ff4c89dc6f9e888e973990d1"
|
||||
"d3154133dcc8bd33b99af9dbf0673390d404d092498a3f214cd93f9b9f28fb5f"
|
||||
"66";
|
||||
static const gchar firmware_public_key_hex[] = "04f06a84ab51a3a6e8ff46868f91dd720e4cdad21f2e090d11e8f9bfc2ea19ee"
|
||||
"1b5eac850b4532968a9399f76cd779e7723e8c2ca73b597c0df5f73b94a36f2b"
|
||||
"6c";
|
||||
static const gchar firmware_hash_hex[] = "c3bf47ea1f4a4a605470313cacb3a44f4a461f68c6faeab07e737610cb5ac835";
|
||||
static const gchar model_signature_hex[] = "febe6ba3107813e185f05189e69ae79d9f7a40802582d94324459844c8b97ec6"
|
||||
"c5daed5462276cb8a193c33e350424b0305d63d79a93a9188dcfc0cb5595f6c1";
|
||||
static const gchar device_signature_hex[] = "10cc57dd8dafb463510a7327a5fca49b698e999b36448e2023eaf0dff0b0d4a3"
|
||||
"4f1caf4e872b77364a0a00d7476554d0324c4cc931937e232a0315837d696c06";
|
||||
static const gchar connect_mac_hex[] = "422bc475a78f972bae842a28e5ad721207457fcbd9a1a3aaf71587c07b84d247";
|
||||
|
||||
/* expected application_secret based on above */
|
||||
|
||||
static const gchar application_secret_hex[] = "13330ba3135ecf5dc71cede01a886540771efab35c8ba053902b2c1ee7de6efe";
|
||||
|
||||
/* test verify_reconnect values */
|
||||
|
||||
static const gchar reconnect_random_hex[] = "8a7451c1d3a8dca1c1330ca50d73454b351a49f46c8e9dcee15c964d295c31c9";
|
||||
static const gchar reconnect_mac_hex[] = "bf3f3bb3bd6ecb2784c160f526f7bc3b3ca8faf5557194c48e0024a0493903c7";
|
||||
|
||||
/* test enrollment_id values */
|
||||
|
||||
static const gchar enrollment_nonce_hex[] = "c2101c44c9a667bba397e81f48b143398603e2c9335a68b409e1dbe71e005ca2";
|
||||
static const gchar enrollment_id_hex[] = "67109dc70a216331f1580ddac601915929c1ff6c9bcba6544ba572c660c3d91e";
|
||||
|
||||
/* test verify_identify values */
|
||||
|
||||
static const gchar identify_nonce_hex[] = "3a1b506f5bec089059acefb9b44dfbdea7a599ee9aa267e5252664d60b798053";
|
||||
static const gchar identify_mac_hex[] = "53a723eef40713094a90c5ef9996cbd6ba268e30676cd7107705a6c3e3e1eff9";
|
||||
@@ -61,6 +61,7 @@ typedef struct
|
||||
FpDeviceFeature features;
|
||||
|
||||
guint64 driver_data;
|
||||
GVariant *persistent_data;
|
||||
|
||||
gint nr_enroll_stages;
|
||||
GSList *sources;
|
||||
|
||||
@@ -54,6 +54,7 @@ enum {
|
||||
PROP_FPI_UDEV_DATA_SPIDEV,
|
||||
PROP_FPI_UDEV_DATA_HIDRAW,
|
||||
PROP_FPI_DRIVER_DATA,
|
||||
PROP_FPI_PERSISTENT_DATA,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
@@ -235,6 +236,8 @@ fp_device_finalize (GObject *object)
|
||||
g_clear_pointer (&priv->udev_data.spidev_path, g_free);
|
||||
g_clear_pointer (&priv->udev_data.hidraw_path, g_free);
|
||||
|
||||
g_clear_pointer (&priv->persistent_data, g_variant_unref);
|
||||
|
||||
G_OBJECT_CLASS (fp_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@@ -304,6 +307,10 @@ fp_device_get_property (GObject *object,
|
||||
g_value_set_string (value, NULL);
|
||||
break;
|
||||
|
||||
case PROP_FPI_PERSISTENT_DATA:
|
||||
g_value_set_variant (value, priv->persistent_data);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
@@ -354,6 +361,11 @@ fp_device_set_property (GObject *object,
|
||||
priv->driver_data = g_value_get_uint64 (value);
|
||||
break;
|
||||
|
||||
case PROP_FPI_PERSISTENT_DATA:
|
||||
g_clear_pointer (&priv->persistent_data, g_variant_unref);
|
||||
priv->persistent_data = g_value_dup_variant (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
@@ -594,6 +606,21 @@ fp_device_class_init (FpDeviceClass *klass)
|
||||
0,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
|
||||
|
||||
/**
|
||||
* FpDevice::fpi-persistent-data: (skip)
|
||||
*
|
||||
* This property is only for internal purposes.
|
||||
*
|
||||
* Stability: private
|
||||
*/
|
||||
properties[PROP_FPI_PERSISTENT_DATA] =
|
||||
g_param_spec_variant ("fpi-persistent-data",
|
||||
"Persistent Driver Data",
|
||||
"Private: Previously stored data for the device",
|
||||
G_VARIANT_TYPE_ANY,
|
||||
NULL,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
}
|
||||
|
||||
@@ -739,6 +766,139 @@ fp_device_get_temperature (FpDevice *device)
|
||||
return priv->temp_current;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_device_get_persistent_data:
|
||||
* @device: A #FpDevice
|
||||
* @data: (array length=length) (transfer full) (out): Return location for data pointer
|
||||
* @length: (transfer full) (out): Length of @data
|
||||
* @error: Return location for error
|
||||
*
|
||||
* Retrieves persistent data that should be stored for this device. Storage
|
||||
* needs to be device specific, i.e. device ID and driver must match when
|
||||
* restored.
|
||||
*
|
||||
* Returns: (type void): %TRUE on success
|
||||
*/
|
||||
gboolean
|
||||
fp_device_get_persistent_data (FpDevice *device,
|
||||
guchar **data,
|
||||
gsize *length,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GVariant) res = NULL;
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
|
||||
g_assert (data);
|
||||
g_assert (length);
|
||||
|
||||
if (priv->persistent_data == NULL)
|
||||
{
|
||||
*data = NULL;
|
||||
*length = 0;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Version + variant from driver */
|
||||
res = g_variant_new ("(issv)",
|
||||
1,
|
||||
fp_device_get_driver (device),
|
||||
priv->device_id,
|
||||
priv->persistent_data);
|
||||
|
||||
*length = g_variant_get_size (res);
|
||||
*data = g_malloc (*length);
|
||||
g_variant_store (res, *data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_device_get_persistent_data:
|
||||
* @device: A #FpDevice
|
||||
* @data: (array length=length) (transfer none): Persistent Data
|
||||
* @length: (transfer none): Length of @data
|
||||
* @error: Return location for error
|
||||
*
|
||||
* Load persistent data from storage. This function should be called after
|
||||
* a device was discovered and before it is opened for the first time. It is
|
||||
* an error to call it if data has already been set (or generated by the
|
||||
* driver).
|
||||
*
|
||||
* Note that the driver may update the data. The API user should retrieve the
|
||||
* value when done with the device and store it in a persistent location.
|
||||
*
|
||||
* Returns: (type void): %TRUE on success
|
||||
*/
|
||||
gboolean
|
||||
fp_device_set_persistent_data (FpDevice *device,
|
||||
guchar *data,
|
||||
gsize length,
|
||||
GError **error)
|
||||
{
|
||||
g_autoptr(GVariant) stored = NULL;
|
||||
g_autoptr(GVariant) loaded = NULL;
|
||||
FpDevicePrivate *priv = fp_device_get_instance_private (device);
|
||||
guchar *copy;
|
||||
gint version;
|
||||
const gchar *device_id;
|
||||
const gchar *driver;
|
||||
|
||||
if (priv->is_open)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
"Data can only be set right after device creation");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (priv->persistent_data)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
|
||||
"Data has already been set");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
g_clear_pointer (&priv->persistent_data, g_variant_unref);
|
||||
g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_FPI_PERSISTENT_DATA]);
|
||||
return TRUE;
|
||||
}
|
||||
g_assert (data);
|
||||
|
||||
copy = g_memdup2 (data, length);
|
||||
stored = g_variant_new_from_data (G_VARIANT_TYPE ("(issv)"), copy, length, FALSE, g_free, copy);
|
||||
|
||||
if (!stored)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
"Data could not be parsed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_variant_get (stored, "(issv)", &version, &driver, &device_id, &loaded);
|
||||
if (version != 1)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
"Unknown data storage version");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (g_strcmp0 (device_id, priv->device_id) != 0 ||
|
||||
g_strcmp0 (driver, fp_device_get_driver (device)) != 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||
"Driver or device ID mismatch!");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_clear_pointer (&priv->persistent_data, g_variant_unref);
|
||||
priv->persistent_data = g_steal_pointer (&loaded);
|
||||
g_object_notify_by_pspec (G_OBJECT (device), properties[PROP_FPI_PERSISTENT_DATA]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_device_supports_identify:
|
||||
* @device: A #FpDevice
|
||||
|
||||
@@ -143,7 +143,6 @@ typedef enum {
|
||||
* @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates
|
||||
* @FP_DEVICE_ERROR_REMOVED: The device has been removed.
|
||||
* @FP_DEVICE_ERROR_TOO_HOT: The device might be getting too hot
|
||||
* @FP_DEVICE_ERROR_UNTRUSTED: Device cannot be trusted
|
||||
*
|
||||
* Error codes for device operations. More specific errors from other domains
|
||||
* such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
|
||||
@@ -162,7 +161,6 @@ typedef enum {
|
||||
/* Leave some room to add more DATA related errors */
|
||||
FP_DEVICE_ERROR_REMOVED = 0x100,
|
||||
FP_DEVICE_ERROR_TOO_HOT,
|
||||
FP_DEVICE_ERROR_UNTRUSTED,
|
||||
} FpDeviceError;
|
||||
|
||||
GQuark fp_device_retry_quark (void);
|
||||
@@ -235,6 +233,15 @@ FpDeviceFeature fp_device_get_features (FpDevice *device);
|
||||
gboolean fp_device_has_feature (FpDevice *device,
|
||||
FpDeviceFeature feature);
|
||||
|
||||
gboolean fp_device_get_persistent_data (FpDevice *device,
|
||||
guchar **data,
|
||||
gsize *length,
|
||||
GError **error);
|
||||
gboolean fp_device_set_persistent_data (FpDevice *device,
|
||||
guchar *data,
|
||||
gsize length,
|
||||
GError **error);
|
||||
|
||||
/* Opening the device */
|
||||
void fp_device_open (FpDevice *device,
|
||||
GCancellable *cancellable,
|
||||
|
||||
@@ -605,7 +605,7 @@ fp_print_equal (FpPrint *self, FpPrint *other)
|
||||
if (g_strcmp0 (self->device_id, other->device_id))
|
||||
return FALSE;
|
||||
|
||||
if (self->type == FPI_PRINT_RAW || self->type == FPI_PRINT_SDCP)
|
||||
if (self->type == FPI_PRINT_RAW)
|
||||
{
|
||||
return g_variant_equal (self->data, other->data);
|
||||
}
|
||||
@@ -870,7 +870,7 @@ fp_print_deserialize (const guchar *data,
|
||||
g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
|
||||
}
|
||||
}
|
||||
else if (type == FPI_PRINT_RAW || type == FPI_PRINT_SDCP)
|
||||
else if (type == FPI_PRINT_RAW)
|
||||
{
|
||||
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);
|
||||
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GBytes *host_private_key;
|
||||
GBytes *host_public_key;
|
||||
GBytes *host_random;
|
||||
GBytes *reconnect_random;
|
||||
GBytes *identify_nonce;
|
||||
GBytes *data;
|
||||
} FpSdcpDevicePrivate;
|
||||
|
||||
void fpi_sdcp_device_get_application_secret (FpSdcpDevice *self,
|
||||
GBytes **application_secret);
|
||||
void fpi_sdcp_device_set_application_secret (FpSdcpDevice *self,
|
||||
GBytes *application_secret);
|
||||
|
||||
void fpi_sdcp_device_open (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_connect (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_reconnect (FpSdcpDevice *self);
|
||||
|
||||
void fpi_sdcp_device_list (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_enroll (FpSdcpDevice *self);
|
||||
void fpi_sdcp_device_identify (FpSdcpDevice *self);
|
||||
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "sdcp_device"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "fp-sdcp-device-private.h"
|
||||
|
||||
/**
|
||||
* SECTION: fp-sdcp-device
|
||||
* @title: FpSdcpDevice
|
||||
* @short_description: SDCP device subclass
|
||||
*
|
||||
* This is a base class for devices implementing the SDCP security protocol.
|
||||
*/
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (FpSdcpDevice, fp_sdcp_device, FP_TYPE_DEVICE)
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_SDCP_DATA,
|
||||
N_PROPS
|
||||
};
|
||||
|
||||
static GParamSpec *properties[N_PROPS];
|
||||
|
||||
/*******************************************************/
|
||||
|
||||
/* Callbacks/vfuncs */
|
||||
static void
|
||||
fp_sdcp_device_open (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_open (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_list (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_list (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_enroll (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_enroll (self);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_identify (FpDevice *device)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
|
||||
|
||||
fpi_sdcp_device_identify (self);
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
|
||||
static void
|
||||
fp_sdcp_device_finalize (GObject *object)
|
||||
{
|
||||
FpSdcpDevice *self = (FpSdcpDevice *) object;
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_clear_pointer (&priv->host_private_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_random, g_bytes_unref);
|
||||
g_clear_pointer (&priv->reconnect_random, g_bytes_unref);
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
g_clear_pointer (&priv->data, g_bytes_unref);
|
||||
|
||||
G_OBJECT_CLASS (fp_sdcp_device_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FpSdcpDevice *self = (FpSdcpDevice *) object;
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SDCP_DATA:
|
||||
g_value_set_boxed (value, priv->data);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
FpSdcpDevice *self = FP_SDCP_DEVICE (object);
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SDCP_DATA:
|
||||
g_clear_pointer (&priv->data, g_bytes_unref);
|
||||
priv->data = g_value_dup_boxed (value);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_constructed (GObject *obj)
|
||||
{
|
||||
G_OBJECT_CLASS (fp_sdcp_device_parent_class)->constructed (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_class_init (FpSdcpDeviceClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
FpDeviceClass *fp_device_class = FP_DEVICE_CLASS (klass);
|
||||
|
||||
object_class->finalize = fp_sdcp_device_finalize;
|
||||
object_class->get_property = fp_sdcp_device_get_property;
|
||||
object_class->set_property = fp_sdcp_device_set_property;
|
||||
object_class->constructed = fp_sdcp_device_constructed;
|
||||
|
||||
fp_device_class->open = fp_sdcp_device_open;
|
||||
fp_device_class->list = fp_sdcp_device_list;
|
||||
fp_device_class->enroll = fp_sdcp_device_enroll;
|
||||
fp_device_class->verify = fp_sdcp_device_identify;
|
||||
fp_device_class->identify = fp_sdcp_device_identify;
|
||||
|
||||
properties[PROP_SDCP_DATA] =
|
||||
g_param_spec_boxed ("sdcp-data",
|
||||
"SDCP Data",
|
||||
"SDCP-related device data that should be persisted and used with the "
|
||||
"device during the current system boot",
|
||||
G_TYPE_BYTES,
|
||||
G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE);
|
||||
|
||||
g_object_class_install_properties (object_class, N_PROPS, properties);
|
||||
|
||||
fpi_device_class_auto_initialize_features (fp_device_class);
|
||||
}
|
||||
|
||||
static void
|
||||
fp_sdcp_device_init (FpSdcpDevice *self)
|
||||
{
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fp-device.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define FP_TYPE_SDCP_DEVICE (fp_sdcp_device_get_type ())
|
||||
G_DECLARE_DERIVABLE_TYPE (FpSdcpDevice, fp_sdcp_device, FP, SDCP_DEVICE, FpDevice)
|
||||
|
||||
G_END_DECLS
|
||||
@@ -190,9 +190,6 @@ fpi_device_error_new (FpDeviceError error)
|
||||
|
||||
case FP_DEVICE_ERROR_TOO_HOT:
|
||||
msg = "Device disabled to prevent overheating.";
|
||||
|
||||
case FP_DEVICE_ERROR_UNTRUSTED:
|
||||
msg = "Could not verify integrity of the device, it cannot be trusted!";
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* FpiLog - Internal logging functions
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "fpi-log.h"
|
||||
|
||||
#undef fp_dbg_hex_dump_bytes
|
||||
#undef fp_dbg_hex_dump_gbytes
|
||||
|
||||
void
|
||||
fp_dbg_hex_dump_bytes (const gchar *log_domain,
|
||||
const guint8 *buf,
|
||||
gsize len)
|
||||
{
|
||||
g_autoptr(GString) line = NULL;
|
||||
|
||||
line = g_string_new ("");
|
||||
|
||||
for (gint i = 0; i < len; i++)
|
||||
{
|
||||
g_string_append_printf (line, "%02x ", buf[i]);
|
||||
if ((i + 1) % 16 == 0)
|
||||
{
|
||||
g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", line->str);
|
||||
g_string_set_size (line, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (line->len)
|
||||
g_log (log_domain, G_LOG_LEVEL_DEBUG, "%s", line->str);
|
||||
}
|
||||
|
||||
void
|
||||
fp_dbg_hex_dump_gbytes (const gchar *log_domain,
|
||||
GBytes *gbytes)
|
||||
{
|
||||
gsize len = 0;
|
||||
const guint8 *buf = g_bytes_get_data (gbytes, &len);
|
||||
|
||||
fp_dbg_hex_dump_bytes (log_domain, buf, len);
|
||||
}
|
||||
@@ -96,32 +96,3 @@
|
||||
* Same as BUG_ON() but is always true.
|
||||
*/
|
||||
#define BUG() BUG_ON (1)
|
||||
|
||||
/*
|
||||
* Custom-defined logging functions are wrapped in macros for convenience so
|
||||
* that the caller does not have to pass G_LOG_DOMAIN every time.
|
||||
*/
|
||||
|
||||
void fp_dbg_hex_dump_bytes (const gchar *log_domain,
|
||||
const guint8 *buf,
|
||||
gsize len);
|
||||
|
||||
/**
|
||||
* fp_dbg_hex_dump_bytes:
|
||||
* @buf: Bytes buffer to dump
|
||||
* @len: Length of @buf to dump
|
||||
*
|
||||
* Prints hex dump of @buf to fp_dbg()
|
||||
*/
|
||||
#define fp_dbg_hex_dump_bytes(buf, len) fp_dbg_hex_dump_bytes (G_LOG_DOMAIN, buf, len)
|
||||
|
||||
void fp_dbg_hex_dump_gbytes (const gchar *log_domain,
|
||||
GBytes *gbytes);
|
||||
|
||||
/**
|
||||
* fp_dbg_hex_dump_gbytes:
|
||||
* @gbytes: #GBytes to dump
|
||||
*
|
||||
* Prints hex dump of @gbytes to fp_dbg()
|
||||
*/
|
||||
#define fp_dbg_hex_dump_gbytes(gbytes) fp_dbg_hex_dump_gbytes (G_LOG_DOMAIN, gbytes)
|
||||
|
||||
@@ -11,13 +11,11 @@ G_BEGIN_DECLS
|
||||
* @FPI_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
|
||||
* @FPI_PRINT_RAW: A raw print where the data is directly compared
|
||||
* @FPI_PRINT_NBIS: NBIS minutiae comparison
|
||||
* @FPI_PRINT_SDCP: Print from an SDCP conforming device
|
||||
*/
|
||||
typedef enum {
|
||||
FPI_PRINT_UNDEFINED = 0,
|
||||
FPI_PRINT_RAW,
|
||||
FPI_PRINT_NBIS,
|
||||
FPI_PRINT_SDCP,
|
||||
} FpiPrintType;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,980 +0,0 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "sdcp_device"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "fpi-compat.h"
|
||||
#include "fpi-print.h"
|
||||
|
||||
#include "fp-sdcp-device-private.h"
|
||||
#include "fpi-sdcp.h"
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
/**
|
||||
* SECTION: fpi-sdcp-device
|
||||
* @title: Internal FpSdcpDevice
|
||||
* @short_description: Internal SDCP device routines
|
||||
*
|
||||
* Internal SDCP handling routines. See #FpSdcpDevice for public routines.
|
||||
*/
|
||||
|
||||
|
||||
G_DEFINE_BOXED_TYPE (FpiSdcpClaim, fpi_sdcp_claim, fpi_sdcp_claim_copy, fpi_sdcp_claim_free)
|
||||
|
||||
/**
|
||||
* fpi_sdcp_claim_new:
|
||||
*
|
||||
* Create an empty #FpiSdcpClaim to provide to the base class.
|
||||
*
|
||||
* Returns: (transfer full): A newly created #FpiSdcpClaim
|
||||
*/
|
||||
FpiSdcpClaim *
|
||||
fpi_sdcp_claim_new (void)
|
||||
{
|
||||
FpiSdcpClaim *res = NULL;
|
||||
|
||||
res = g_new0 (FpiSdcpClaim, 1);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_claim_free:
|
||||
* @claim: a #FpiSdcpClaim
|
||||
*
|
||||
* Release the memory used by an #FpiSdcpClaim.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_claim_free (FpiSdcpClaim *claim)
|
||||
{
|
||||
g_return_if_fail (claim);
|
||||
|
||||
g_clear_pointer (&claim->model_certificate, g_bytes_unref);
|
||||
g_clear_pointer (&claim->device_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&claim->firmware_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&claim->firmware_hash, g_bytes_unref);
|
||||
g_clear_pointer (&claim->model_signature, g_bytes_unref);
|
||||
g_clear_pointer (&claim->device_signature, g_bytes_unref);
|
||||
|
||||
g_free (claim);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_claim_copy:
|
||||
* @other: The #FpiSdcpClaim to copy
|
||||
*
|
||||
* Create a (shallow) copy of a #FpiSdcpClaim.
|
||||
*
|
||||
* Returns: (transfer full): A newly created #FpiSdcpClaim
|
||||
*/
|
||||
FpiSdcpClaim *
|
||||
fpi_sdcp_claim_copy (FpiSdcpClaim *other)
|
||||
{
|
||||
FpiSdcpClaim *res = NULL;
|
||||
|
||||
res = fpi_sdcp_claim_new ();
|
||||
|
||||
if (other->model_certificate)
|
||||
res->model_certificate = g_bytes_ref (other->model_certificate);
|
||||
if (other->device_public_key)
|
||||
res->device_public_key = g_bytes_ref (other->device_public_key);
|
||||
if (other->firmware_public_key)
|
||||
res->firmware_public_key = g_bytes_ref (other->firmware_public_key);
|
||||
if (other->firmware_hash)
|
||||
res->firmware_hash = g_bytes_ref (other->firmware_hash);
|
||||
if (other->model_signature)
|
||||
res->model_signature = g_bytes_ref (other->model_signature);
|
||||
if (other->device_signature)
|
||||
res->device_signature = g_bytes_ref (other->device_signature);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Manually redefine what G_DEFINE_* macro does */
|
||||
static inline gpointer
|
||||
fp_sdcp_device_get_instance_private (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *sdcp_class = g_type_class_peek_static (FP_TYPE_SDCP_DEVICE);
|
||||
|
||||
return G_STRUCT_MEMBER_P (self,
|
||||
g_type_class_get_instance_private_offset (sdcp_class));
|
||||
}
|
||||
|
||||
/* Example values from Microsoft's SDCP documentation to use when testing (FP_DEVICE_EMULATION=1) */
|
||||
static const guchar test_host_private_key[] = {
|
||||
0x84, 0x00, 0xed, 0x14, 0x57, 0x9c, 0xdf, 0x11, 0x58, 0x64, 0x77, 0xe8, 0x36, 0xe8, 0xcb, 0x52,
|
||||
0x70, 0x84, 0x41, 0xc1, 0xc2, 0xa4, 0x47, 0xc2, 0x18, 0xc5, 0xbb, 0xc2, 0xd1, 0x18, 0xfb, 0xc7
|
||||
};
|
||||
static const guchar test_host_public_key[] = {
|
||||
0x04, 0x52, 0xf0, 0x56, 0xff, 0xb9, 0xc6, 0x72, 0x86, 0x54, 0x77, 0x1a, 0x36, 0x29, 0xb7, 0x70,
|
||||
0x76, 0x7b, 0x19, 0xa2, 0x10, 0x6a, 0x49, 0x16, 0xfb, 0x81, 0xba, 0x06, 0xef, 0x67, 0x97, 0xc4,
|
||||
0xa3, 0xdf, 0x67, 0x2a, 0xde, 0x0e, 0x91, 0x16, 0xd1, 0xab, 0xe2, 0x78, 0xa8, 0x22, 0x3a, 0xbd,
|
||||
0xe4, 0x95, 0x8d, 0x62, 0xd4, 0xff, 0x68, 0x82, 0x15, 0x9f, 0x06, 0x17, 0xc6, 0xf8, 0xce, 0x10,
|
||||
0xbf
|
||||
};
|
||||
static const gchar test_host_random[] = {
|
||||
0xd8, 0x77, 0x40, 0x3a, 0xbe, 0x82, 0xf4, 0xd9, 0x7e, 0x14, 0x48, 0xc5, 0x05, 0x2d, 0x83, 0xa5,
|
||||
0x32, 0xa4, 0x5e, 0x56, 0xef, 0x04, 0x9c, 0xbb, 0xf9, 0x81, 0x13, 0x75, 0x20, 0xe7, 0x13, 0xbf
|
||||
};
|
||||
static const gchar test_reconnect_random[] = {
|
||||
0x8a, 0x74, 0x51, 0xc1, 0xd3, 0xa8, 0xdc, 0xa1, 0xc1, 0x33, 0x0c, 0xa5, 0x0d, 0x73, 0x45, 0x4b,
|
||||
0x35, 0x1a, 0x49, 0xf4, 0x6c, 0x8e, 0x9d, 0xce, 0xe1, 0x5c, 0x96, 0x4d, 0x29, 0x5c, 0x31, 0xc9
|
||||
};
|
||||
static const gchar test_identify_nonce[] = {
|
||||
0x3a, 0x1b, 0x50, 0x6f, 0x5b, 0xec, 0x08, 0x90, 0x59, 0xac, 0xef, 0xb9, 0xb4, 0x4d, 0xfb, 0xde,
|
||||
0xa7, 0xa5, 0x99, 0xee, 0x9a, 0xa2, 0x67, 0xe5, 0x25, 0x26, 0x64, 0xd6, 0x0b, 0x79, 0x80, 0x53
|
||||
};
|
||||
|
||||
/* FpiSdcpDevice */
|
||||
|
||||
/* Internal functions of FpSdcpDevice */
|
||||
|
||||
void
|
||||
fpi_sdcp_device_get_application_secret (FpSdcpDevice *self,
|
||||
GBytes **application_secret)
|
||||
{
|
||||
GBytes *data = NULL;
|
||||
|
||||
g_return_if_fail (*application_secret == NULL);
|
||||
|
||||
g_object_get (G_OBJECT (self), "sdcp-data", &data, NULL);
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
*application_secret = g_steal_pointer (&data);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_set_application_secret (FpSdcpDevice *self,
|
||||
GBytes *application_secret)
|
||||
{
|
||||
g_return_if_fail (application_secret);
|
||||
|
||||
g_object_set (G_OBJECT (self), "sdcp-data", application_secret, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_open (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_OPEN);
|
||||
|
||||
cls->open (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_connect (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
GError *error = NULL;
|
||||
|
||||
g_clear_pointer (&priv->host_private_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_random, g_bytes_unref);
|
||||
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
|
||||
{
|
||||
/* SDCP Connect: 3.i. Generate host ephemeral ECDH key pair */
|
||||
fpi_sdcp_generate_host_key (&priv->host_private_key, &priv->host_public_key, &error);
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_connect_complete (self,
|
||||
NULL, NULL, NULL,
|
||||
error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* SDCP Connect: 3.ii. Generate host random */
|
||||
priv->host_random = fpi_sdcp_generate_random (&error);
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_connect_complete (self,
|
||||
NULL, NULL, NULL,
|
||||
error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use Microsoft's SDCP documentation example values in emulation mode */
|
||||
priv->host_private_key = g_bytes_new (test_host_private_key, sizeof (test_host_private_key));
|
||||
priv->host_public_key = g_bytes_new (test_host_public_key, sizeof (test_host_public_key));
|
||||
priv->host_random = g_bytes_new (test_host_random, sizeof (test_host_random));
|
||||
}
|
||||
|
||||
/* SDCP Connect: 3.iii. Send the Connect message */
|
||||
cls->connect (self);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_reconnect (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
GError *error = NULL;
|
||||
|
||||
g_clear_pointer (&priv->reconnect_random, g_bytes_unref);
|
||||
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
|
||||
{
|
||||
/* SDCP Reconnect: 2.i. Generate host random */
|
||||
priv->reconnect_random = fpi_sdcp_generate_random (&error);
|
||||
if (error)
|
||||
{
|
||||
fpi_sdcp_device_reconnect_complete (self, NULL, error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use Microsoft's SDCP documentation example value in emulation mode */
|
||||
priv->reconnect_random = g_bytes_new (test_reconnect_random, sizeof (test_reconnect_random));
|
||||
}
|
||||
|
||||
/* SDCP Reconnect: 2.ii. Send the Reconnect message */
|
||||
if (cls->reconnect)
|
||||
cls->reconnect (self);
|
||||
else
|
||||
fpi_sdcp_device_connect (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_list (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_LIST);
|
||||
|
||||
cls->list (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_enroll (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpPrint *print;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_ENROLL);
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
g_return_if_fail (application_secret != NULL);
|
||||
|
||||
fpi_device_get_enroll_data (FP_DEVICE (self), &print);
|
||||
|
||||
fpi_print_set_device_stored (print, FALSE);
|
||||
g_object_set (print, "fpi-data", NULL, NULL);
|
||||
|
||||
cls->enroll (self);
|
||||
}
|
||||
|
||||
void
|
||||
fpi_sdcp_device_identify (FpSdcpDevice *self)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpiDeviceAction action;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_IDENTIFY || action == FPI_DEVICE_ACTION_VERIFY);
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
g_return_if_fail (application_secret != NULL);
|
||||
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
|
||||
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") != 0)
|
||||
{
|
||||
/* Generate a new nonce. */
|
||||
priv->identify_nonce = fpi_sdcp_generate_random (&error);
|
||||
if (error)
|
||||
{
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use Microsoft's SDCP documentation example value in emulation mode */
|
||||
priv->identify_nonce = g_bytes_new (test_identify_nonce, sizeof (test_identify_nonce));
|
||||
}
|
||||
|
||||
cls->identify (self);
|
||||
}
|
||||
|
||||
/*********************************************************/
|
||||
/* Private API */
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_open_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of open operation. Responsible for triggering SDCP connect
|
||||
* or reconnect as necessary.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_open_complete (FpSdcpDevice *self,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
|
||||
if (!error)
|
||||
{
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
|
||||
/* Try a reconnect if implemented and we already have an application_secret */
|
||||
if (cls->reconnect && application_secret)
|
||||
fpi_sdcp_device_reconnect (self);
|
||||
|
||||
/* Connect if we don't already have an application_secret */
|
||||
else if (!application_secret)
|
||||
fpi_sdcp_device_connect (self);
|
||||
|
||||
/* Complete open if we are already connected */
|
||||
else
|
||||
fpi_device_open_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_sdcp_device_get_connect_data:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @host_random: (out) (transfer full): The host-generated random
|
||||
* @host_public_key: (out) (transfer full): The host public key
|
||||
*
|
||||
* Get data required to connect to (i.e. open) the device securely.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_get_connect_data (FpSdcpDevice *self,
|
||||
GBytes **host_random,
|
||||
GBytes **host_public_key)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (host_random != NULL);
|
||||
g_return_if_fail (host_public_key != NULL);
|
||||
g_return_if_fail (priv->host_random);
|
||||
g_return_if_fail (priv->host_public_key);
|
||||
|
||||
*host_random = g_bytes_new_from_bytes (priv->host_random, 0,
|
||||
g_bytes_get_size (priv->host_random));
|
||||
*host_public_key = g_bytes_new_from_bytes (priv->host_public_key, 0,
|
||||
g_bytes_get_size (priv->host_public_key));
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_sdcp_device_get_reconnect_data:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @reconnect_random: (out) (transfer full): The host-generated random
|
||||
*
|
||||
* Get data required to reconnect to (i.e. open) to the device securely.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_get_reconnect_data (FpSdcpDevice *self,
|
||||
GBytes **reconnect_random)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (reconnect_random != NULL);
|
||||
g_return_if_fail (priv->reconnect_random);
|
||||
|
||||
*reconnect_random = g_bytes_new_from_bytes (priv->reconnect_random, 0,
|
||||
g_bytes_get_size (priv->reconnect_random));
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_sdcp_device_get_identify_data:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @nonce: (out) (transfer full): A new host-generated nonce
|
||||
*
|
||||
* Get data required to identify a new print.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_get_identify_data (FpSdcpDevice *self,
|
||||
GBytes **nonce)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (nonce != NULL);
|
||||
g_return_if_fail (priv->identify_nonce);
|
||||
|
||||
*nonce = g_bytes_new_from_bytes (priv->identify_nonce, 0,
|
||||
g_bytes_get_size (priv->identify_nonce));
|
||||
}
|
||||
|
||||
/**
|
||||
* fp_sdcp_device_set_identify_data:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @nonce: A driver-specified nonce
|
||||
*
|
||||
* Sets data required to identify a new print.
|
||||
*
|
||||
* Most drivers should not use this function, but instead use the automatically
|
||||
* generated values retrieved from fpi_sdcp_device_get_identify_data() when
|
||||
* executing the device-specific Identify command.
|
||||
*
|
||||
* In cases where a device's Identify command does not accept a randomly
|
||||
* generated nonce, this function can be used to override the randomly generated
|
||||
* nonce to the nonce that was actually sent to the device.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_set_identify_data (FpSdcpDevice *self,
|
||||
GBytes *nonce)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_return_if_fail (nonce != NULL);
|
||||
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
|
||||
priv->identify_nonce = g_steal_pointer (&nonce);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_connect_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @device_random: The device random
|
||||
* @claim: The device #FpiSdcpClaim
|
||||
* @mac: The MAC authenticating @claim
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of connect operation. Responsible for performing SDCP key
|
||||
* agreement, deriving secrets necessary for processing all other SDCP-related
|
||||
* payloads, and verifying the device connection is trusted.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_connect_complete (FpSdcpDevice *self,
|
||||
GBytes *device_random,
|
||||
FpiSdcpClaim *claim,
|
||||
GBytes *mac,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpiDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_OPEN);
|
||||
g_return_if_fail (priv->host_private_key);
|
||||
g_return_if_fail (priv->host_random);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (device_random || claim || mac)
|
||||
{
|
||||
g_clear_pointer (&device_random, g_bytes_unref);
|
||||
g_clear_pointer (&claim, fpi_sdcp_claim_free);
|
||||
g_clear_pointer (&mac, g_bytes_unref);
|
||||
fp_warn ("Driver provided SDCP Connect information but also reported error.");
|
||||
}
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device_random || !claim || !mac ||
|
||||
(!claim->model_certificate || !claim->device_public_key || !claim->firmware_public_key ||
|
||||
!claim->firmware_hash || !claim->model_signature || !claim->device_signature))
|
||||
{
|
||||
fp_dbg ("Driver did not provide all required information to callback; returning error instead.");
|
||||
g_clear_pointer (&device_random, g_bytes_unref);
|
||||
g_clear_pointer (&claim, fpi_sdcp_claim_free);
|
||||
g_clear_pointer (&mac, g_bytes_unref);
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self),
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
||||
"Driver called connect complete with "
|
||||
"incomplete arguments"));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify connect and store the application_secret */
|
||||
if (!fpi_sdcp_verify_connect (priv->host_private_key,
|
||||
priv->host_random,
|
||||
device_random,
|
||||
claim,
|
||||
mac,
|
||||
!cls->ignore_device_certificate,
|
||||
!cls->ignore_device_signatures,
|
||||
&application_secret,
|
||||
&error))
|
||||
{
|
||||
fpi_device_open_complete (FP_DEVICE (self),
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_UNTRUSTED,
|
||||
"SDCP Connect verification failed: %s",
|
||||
error->message));
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_sdcp_device_set_application_secret (self, application_secret);
|
||||
|
||||
/* Clear no longer needed private data */
|
||||
g_clear_pointer (&priv->host_private_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_public_key, g_bytes_unref);
|
||||
g_clear_pointer (&priv->host_random, g_bytes_unref);
|
||||
|
||||
fpi_device_open_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_reconnect_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @mac: The MAC authenticating @claim
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Reports completion of a reconnect (i.e. open) operation.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_reconnect_complete (FpSdcpDevice *self,
|
||||
GBytes *mac,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpiDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_OPEN);
|
||||
g_return_if_fail (priv->reconnect_random);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (mac)
|
||||
{
|
||||
fp_warn ("Driver provided a reconnect MAC but also reported an error.");
|
||||
g_clear_pointer (&mac, g_bytes_unref);
|
||||
}
|
||||
|
||||
/* Silently try a normal connect instead. */
|
||||
fpi_sdcp_device_connect (self);
|
||||
}
|
||||
else if (mac)
|
||||
{
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
|
||||
if (fpi_sdcp_verify_reconnect (application_secret, priv->reconnect_random, mac, &error))
|
||||
{
|
||||
fp_dbg ("SDCP Reconnect succeeded");
|
||||
fpi_device_open_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fp_dbg ("SDCP Reconnect failed; doing a full connect.");
|
||||
fpi_sdcp_device_connect (self);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_open_complete (FP_DEVICE (self),
|
||||
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
|
||||
"Driver called reconnect complete with wrong arguments"));
|
||||
}
|
||||
|
||||
/* Clear no longer needed private data */
|
||||
g_clear_pointer (&priv->reconnect_random, g_bytes_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_list_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @ids: A #GPtrArray of #GBytes of each SDCP enrollment ID stored on the device
|
||||
* @error: A #GError or %NULL on success
|
||||
*
|
||||
* Convenience function to create the minimally required #FpPrint list for
|
||||
* #FpSdcpDevice prints using the provided @ids, then uses that #FpPrint list to
|
||||
* report completion of the list operation.
|
||||
*
|
||||
* If the device provides additional attributes that should be stored on each
|
||||
* #FpPrint as part of the list operation, a #GPtrArray of #FpPrint can instead
|
||||
* be created with the additional attributes and fpi_device_list_complete() can
|
||||
* be used instead of this function.
|
||||
*
|
||||
* Please note that the @ids array will be freed using g_ptr_array_unref() and
|
||||
* the elements are destroyed automatically. As such, you must use
|
||||
* g_ptr_array_new_with_free_func() with `(GDestroyNotify) g_bytes_unref` as the
|
||||
* free func when creating the #GPtrArray.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_list_complete (FpSdcpDevice *self,
|
||||
GPtrArray *ids,
|
||||
GError *error)
|
||||
{
|
||||
g_autoptr(GPtrArray) prints = NULL;
|
||||
gint prints_len = 0;
|
||||
FpiDeviceAction action;
|
||||
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_LIST);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_device_list_complete (FP_DEVICE (self), NULL, error);
|
||||
return;
|
||||
}
|
||||
|
||||
prints = g_ptr_array_new_with_free_func (g_object_unref);
|
||||
|
||||
/* Allow an empty array (prints_len=0) but if ids has been passed, use it */
|
||||
if (ids)
|
||||
prints_len = ids->len;
|
||||
|
||||
for (gint i = 0; i < prints_len; i++)
|
||||
{
|
||||
FpPrint *print = fp_print_new (FP_DEVICE (self));
|
||||
fpi_print_set_type (print, FPI_PRINT_SDCP);
|
||||
fpi_print_set_device_stored (print, FALSE);
|
||||
fpi_sdcp_device_set_print_id (print, g_ptr_array_index (ids, i));
|
||||
g_ptr_array_add (prints, g_object_ref_sink (print));
|
||||
}
|
||||
|
||||
fpi_device_list_complete (FP_DEVICE (self), g_steal_pointer (&prints), NULL);
|
||||
|
||||
g_clear_pointer (&ids, g_ptr_array_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_enroll_commit:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @nonce: The device generated nonce
|
||||
* @error: a #GError or %NULL on success
|
||||
*
|
||||
* Called when the print is ready to be committed to device memory.
|
||||
* During enrollment, fpi_device_enroll_progress() must be called for each
|
||||
* successful stage before the print can be committed.
|
||||
* The @nonce generated by the device-specific EnrollmentNonce response must be
|
||||
* provided in order for the enrollment ID to be generated.
|
||||
* The driver's enroll_commit() vfunc will be triggered upon successfully
|
||||
* generating the enrollment ID.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_enroll_commit (FpSdcpDevice *self,
|
||||
GBytes *nonce,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
GBytes *id = NULL;
|
||||
FpPrint *print;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_ENROLL);
|
||||
g_return_if_fail (nonce != NULL);
|
||||
|
||||
fpi_device_get_enroll_data (FP_DEVICE (self), &print);
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
|
||||
id = fpi_sdcp_generate_enrollment_id (application_secret, nonce, &error);
|
||||
if (!id || error)
|
||||
{
|
||||
fp_warn ("Could not generate SDCP enrollment ID");
|
||||
fpi_device_enroll_complete (FP_DEVICE (self), NULL, error);
|
||||
g_object_set (print, "fpi-data", NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set to true once committed */
|
||||
fpi_print_set_device_stored (print, FALSE);
|
||||
|
||||
/* Attach the ID to the print */
|
||||
fpi_sdcp_device_set_print_id (print, id);
|
||||
|
||||
cls->enroll_commit (self, id);
|
||||
|
||||
g_clear_pointer (&id, g_bytes_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_enroll_commit_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @error: a #GError or %NULL on success
|
||||
*
|
||||
* Called when device has committed the given print to memory.
|
||||
* This finalizes the enroll operation.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_enroll_commit_complete (FpSdcpDevice *self,
|
||||
GError *error)
|
||||
{
|
||||
g_autoptr(GBytes) id = NULL;
|
||||
FpPrint *print;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
g_return_if_fail (fpi_device_get_current_action (FP_DEVICE (self)) == FPI_DEVICE_ACTION_ENROLL);
|
||||
|
||||
if (error)
|
||||
{
|
||||
fpi_device_enroll_complete (FP_DEVICE (self), NULL, error);
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_device_get_enroll_data (FP_DEVICE (self), &print);
|
||||
|
||||
fpi_sdcp_device_get_print_id (print, &id);
|
||||
if (!id)
|
||||
{
|
||||
g_error ("Inconsistent state; the print must have the enrolled ID attached at this point");
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_print_set_type (print, FPI_PRINT_SDCP);
|
||||
fpi_print_set_device_stored (print, TRUE);
|
||||
|
||||
fpi_device_enroll_complete (FP_DEVICE (self), g_object_ref (print), NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_identify_retry:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @error: a #GError containing the retry condition
|
||||
*
|
||||
* Called when the device requires the finger to be presented again.
|
||||
* This should not be called for a verified no-match, it should only
|
||||
* be called if e.g. the finger was not centered properly or similar.
|
||||
*
|
||||
* Effectively this simply raises the error up. This function exists
|
||||
* to bridge the difference in semantics that SDPC has from how
|
||||
* libfprint works internally.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_identify_retry (FpSdcpDevice *self,
|
||||
GError *error)
|
||||
{
|
||||
FpiDeviceAction action;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_IDENTIFY || action == FPI_DEVICE_ACTION_VERIFY);
|
||||
|
||||
if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_ERROR, NULL, error);
|
||||
else if (action == FPI_DEVICE_ACTION_IDENTIFY)
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_identify_complete:
|
||||
* @self: a #FpSdcpDevice fingerprint device
|
||||
* @id: (transfer none): the ID as reported by the device
|
||||
* @mac: (transfer none): MAC authenticating the message
|
||||
* @error: (transfer full): #GError if an error occured
|
||||
*
|
||||
* Called when device is done with the identification routine. The
|
||||
* returned ID may be %NULL if none of the in-device templates matched.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_identify_complete (FpSdcpDevice *self,
|
||||
GBytes *id,
|
||||
GBytes *mac,
|
||||
GError *error)
|
||||
{
|
||||
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
|
||||
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
FpPrint *identified_print;
|
||||
FpiDeviceAction action;
|
||||
|
||||
g_return_if_fail (FP_IS_SDCP_DEVICE (self));
|
||||
action = fpi_device_get_current_action (FP_DEVICE (self));
|
||||
|
||||
g_return_if_fail (action == FPI_DEVICE_ACTION_IDENTIFY || action == FPI_DEVICE_ACTION_VERIFY);
|
||||
g_return_if_fail (priv->identify_nonce);
|
||||
|
||||
if (error)
|
||||
{
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* No error and no valid id/mac provided means that there was no match from the device */
|
||||
if (!id || !mac || g_bytes_get_size (id) != SDCP_ENROLLMENT_ID_SIZE ||
|
||||
g_bytes_get_size (mac) != SDCP_MAC_SIZE)
|
||||
{
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_FAIL, NULL, NULL);
|
||||
fpi_device_verify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, NULL, NULL);
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
fpi_sdcp_device_get_application_secret (self, &application_secret);
|
||||
|
||||
if (!fpi_sdcp_verify_identify (application_secret, priv->identify_nonce, id, mac, &error))
|
||||
{
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
fpi_device_action_error (FP_DEVICE (self), error);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear no longer needed private data */
|
||||
g_clear_pointer (&priv->identify_nonce, g_bytes_unref);
|
||||
|
||||
/* Create a new print */
|
||||
identified_print = fp_print_new (FP_DEVICE (self));
|
||||
|
||||
fpi_print_set_type (identified_print, FPI_PRINT_SDCP);
|
||||
|
||||
/* Set to true once committed */
|
||||
fpi_print_set_device_stored (identified_print, FALSE);
|
||||
|
||||
/* Attach the ID to the print */
|
||||
fpi_sdcp_device_set_print_id (identified_print, id);
|
||||
|
||||
|
||||
/* The surrounding API expects a match/no-match against a given set. */
|
||||
if (action == FPI_DEVICE_ACTION_VERIFY)
|
||||
{
|
||||
FpPrint *print;
|
||||
|
||||
fpi_device_get_verify_data (FP_DEVICE (self), &print);
|
||||
|
||||
if (fp_print_equal (print, identified_print))
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_SUCCESS, identified_print, NULL);
|
||||
else
|
||||
fpi_device_verify_report (FP_DEVICE (self), FPI_MATCH_FAIL, identified_print, NULL);
|
||||
|
||||
fpi_device_verify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
GPtrArray *prints;
|
||||
gint i;
|
||||
|
||||
fpi_device_get_identify_data (FP_DEVICE (self), &prints);
|
||||
|
||||
for (i = 0; i < prints->len; i++)
|
||||
{
|
||||
FpPrint *print = g_ptr_array_index (prints, i);
|
||||
|
||||
if (fp_print_equal (print, identified_print))
|
||||
{
|
||||
fpi_device_identify_report (FP_DEVICE (self), print, identified_print, NULL);
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Print wasn't in database. */
|
||||
fpi_device_identify_report (FP_DEVICE (self), NULL, identified_print, NULL);
|
||||
fpi_device_identify_complete (FP_DEVICE (self), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_get_print_id:
|
||||
* @print: an SDCP device #FpPrint
|
||||
* @id: (out) (transfer full): the ID gotten from the @print data
|
||||
*
|
||||
* Gets the SDCP enrollment ID from the @print data.
|
||||
*
|
||||
* The returned @id may be %NULL if the data was not set or in the wrong format.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_get_print_id (FpPrint *print,
|
||||
GBytes **id)
|
||||
{
|
||||
g_autoptr(GVariant) id_var = NULL;
|
||||
g_autoptr(GVariant) data = NULL;
|
||||
const guint8 *id_data;
|
||||
gsize id_len;
|
||||
|
||||
g_return_if_fail (print);
|
||||
g_return_if_fail (*id == NULL);
|
||||
|
||||
g_object_get (G_OBJECT (print), "fpi-data", &data, NULL);
|
||||
|
||||
if (!data)
|
||||
{
|
||||
fp_warn ("SDCP print data has not been set.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_variant_check_format_string (data, "(@ay)", FALSE))
|
||||
{
|
||||
fp_warn ("SDCP print data is not in expected format.");
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (data, "(@ay)", &id_var);
|
||||
|
||||
id_data = g_variant_get_fixed_array (id_var, &id_len, sizeof (guint8));
|
||||
|
||||
*id = g_bytes_new (id_data, id_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* fpi_sdcp_device_set_print_id:
|
||||
* @print: an SDCP device #FpPrint
|
||||
* @id: the ID to set in the @print data
|
||||
*
|
||||
* Sets the SDCP enrollment ID in the @print data.
|
||||
*/
|
||||
void
|
||||
fpi_sdcp_device_set_print_id (FpPrint *print,
|
||||
GBytes *id)
|
||||
{
|
||||
GVariant *id_var;
|
||||
GVariant *data;
|
||||
|
||||
g_return_if_fail (print);
|
||||
g_return_if_fail (id);
|
||||
|
||||
id_var = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
|
||||
g_bytes_get_data (id, NULL),
|
||||
g_bytes_get_size (id),
|
||||
1);
|
||||
data = g_variant_new ("(@ay)", id_var);
|
||||
|
||||
g_object_set (G_OBJECT (print), "fpi-data", data, NULL);
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
/*
|
||||
* FpSdcpDevice - A base class for SDCP enabled devices
|
||||
* Copyright (C) 2020 Benjamin Berg <bberg@redhat.com>
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-device.h"
|
||||
|
||||
#include "fp-sdcp-device.h"
|
||||
|
||||
#define SDCP_PUBLIC_KEY_SIZE 65
|
||||
#define SDCP_APPLICATION_SECRET_SIZE 32
|
||||
#define SDCP_RANDOM_SIZE 32
|
||||
#define SDCP_MAC_SIZE 32
|
||||
#define SDCP_NONCE_SIZE 32
|
||||
#define SDCP_ENROLLMENT_ID_SIZE 32
|
||||
#define SDCP_SIGNATURE_SIZE 64
|
||||
|
||||
/**
|
||||
* FpiSdcpClaim:
|
||||
* @model_certificate: Microsoft-issued per-model certificate encoded in x509
|
||||
* ASN.1 DER format (`cert_m`)
|
||||
* @device_public_key: The per-device ECDSA public key (`pk_d`)
|
||||
* @firmware_public_key: The ephemeral public key generated by the device
|
||||
* firmware (`pk_f`)
|
||||
* @firmware_hash: Hash of the firmware and firmware public key (`h_f`)
|
||||
* @model_signature: Device public key signed by the model key (`s_m`)
|
||||
* @device_signature: Firmware hash and public key signed by the device private
|
||||
* key (`s_d`)
|
||||
*
|
||||
* Structure to hold the claim as produced by the device during a secure
|
||||
* connect. See the SDCP specification for more details.
|
||||
*
|
||||
* Note all of these may simply be memory views into a larger #GBytes created
|
||||
* using g_bytes_new_from_bytes().
|
||||
*/
|
||||
struct _FpiSdcpClaim
|
||||
{
|
||||
/*< public >*/
|
||||
GBytes *model_certificate; /* cert_m */
|
||||
GBytes *device_public_key; /* pk_d */
|
||||
GBytes *firmware_public_key; /* pk_f */
|
||||
GBytes *firmware_hash; /* h_f */
|
||||
GBytes *model_signature; /* s_m */
|
||||
GBytes *device_signature; /* s_d */
|
||||
};
|
||||
typedef struct _FpiSdcpClaim FpiSdcpClaim;
|
||||
|
||||
GType fpi_sdcp_claim_get_type (void) G_GNUC_CONST;
|
||||
FpiSdcpClaim *fpi_sdcp_claim_new (void);
|
||||
FpiSdcpClaim *fpi_sdcp_claim_copy (FpiSdcpClaim *other);
|
||||
void fpi_sdcp_claim_free (FpiSdcpClaim *claim);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (FpiSdcpClaim, fpi_sdcp_claim_free)
|
||||
|
||||
|
||||
/**
|
||||
* FpSdcpDeviceClass:
|
||||
* @ignore_device_certificate: Set to %TRUE to skip validating the device's
|
||||
* #FpiSdcpClaim.model_certificate against the SDCP truststore.
|
||||
* @ignore_device_signatures: Set to %TRUE to skip verifying the device's
|
||||
* #FpiSdcpClaim.model_signature and #FpiSdcpClaim.device_signature.
|
||||
* @open: Open the device. Similar to #FpDeviceClass.open except that
|
||||
* completion with fpi_sdcp_device_open_complete() will also take care of
|
||||
* executing @connect and @reconnect as necessary.
|
||||
* @connect: Establish SDCP connection.
|
||||
* @reconnect: Perform a faster reconnect. Drivers do not need to provide this
|
||||
* function. If reconnect fails, then a normal connect will be tried.
|
||||
* @list: List prints stored on the device. The driver must create a #GPtrArray
|
||||
* of #GBytes with each enrollment ID stored on the device and use it to call
|
||||
* fpi_sdcp_device_list_complete() in order to complete the operation.
|
||||
* @enroll: Start the enrollment procedure and capture all samples. The driver
|
||||
* must report enrollment progress using fpi_device_enroll_progress(). It
|
||||
* should also store available metadata about the print in device memory. The
|
||||
* driver must call fpi_sdcp_device_enroll_commit() when all enrollment stages
|
||||
* are complete and the print is ready to be commited to the device.
|
||||
* @enroll_commit: Commit the newly-enrolled print to the device memory using
|
||||
* the passed id. id may be %NULL, in which case the driver must abort the
|
||||
* enrollment process. id is owned by the base class and remains valid
|
||||
* throughout the operation. On completion, the driver must call
|
||||
* fpi_sdcp_device_enroll_commit_complete().
|
||||
* @identify: Start identification process. On completion, the driver must call
|
||||
* fpi_sdcp_device_identify_complete(). To request the user to retry the
|
||||
* fpi_sdcp_device_identify_retry() function is used.
|
||||
*
|
||||
* These are the main entry points for drivers implementing SDCP.
|
||||
*
|
||||
* Drivers *must* eventually call the corresponding function to finish the
|
||||
* operation.
|
||||
*
|
||||
* The following #FpDeviceClass entry points are also compatible and can be set
|
||||
* on the #FpDeviceClass if supported for a given device:
|
||||
* - #FpDeviceClass.probe
|
||||
* - #FpDeviceClass.close
|
||||
* - #FpDeviceClass.delete
|
||||
* - #FpDeviceClass.clear_storage
|
||||
* - #FpDeviceClass.cancel
|
||||
* - #FpDeviceClass.suspend
|
||||
* - #FpDeviceClass.resume
|
||||
*
|
||||
* XXX: Is the use of fpi_device_action_error() acceptable?
|
||||
*
|
||||
* Drivers *must* also handle cancellation properly for any long running
|
||||
* operation (i.e. any operation that requires capturing). It is entirely fine
|
||||
* to ignore cancellation requests for short operations (e.g. open/close).
|
||||
*
|
||||
* This API is solely intended for drivers. It is purely internal and neither
|
||||
* API nor ABI stable.
|
||||
*/
|
||||
struct _FpSdcpDeviceClass
|
||||
{
|
||||
FpDeviceClass parent_class;
|
||||
|
||||
gboolean ignore_device_certificate;
|
||||
gboolean ignore_device_signatures;
|
||||
|
||||
void (*open) (FpSdcpDevice *sdcp_device);
|
||||
void (*connect) (FpSdcpDevice *sdcp_device);
|
||||
void (*reconnect) (FpSdcpDevice *sdcp_device);
|
||||
void (*list) (FpSdcpDevice *sdcp_device);
|
||||
void (*enroll) (FpSdcpDevice *sdcp_device);
|
||||
void (*enroll_commit) (FpSdcpDevice *sdcp_device,
|
||||
GBytes *id);
|
||||
void (*identify) (FpSdcpDevice *sdcp_device);
|
||||
};
|
||||
|
||||
void fpi_sdcp_device_open_complete (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_connect_data (FpSdcpDevice *self,
|
||||
GBytes **host_random,
|
||||
GBytes **host_public_key);
|
||||
void fpi_sdcp_device_connect_complete (FpSdcpDevice *self,
|
||||
GBytes *device_random,
|
||||
FpiSdcpClaim *claim,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_reconnect_data (FpSdcpDevice *self,
|
||||
GBytes **reconnect_random);
|
||||
void fpi_sdcp_device_reconnect_complete (FpSdcpDevice *self,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_list_complete (FpSdcpDevice *self,
|
||||
GPtrArray *ids,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_enroll_commit (FpSdcpDevice *self,
|
||||
GBytes *nonce,
|
||||
GError *error);
|
||||
void fpi_sdcp_device_enroll_commit_complete (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_identify_data (FpSdcpDevice *self,
|
||||
GBytes **nonce);
|
||||
void fpi_sdcp_device_set_identify_data (FpSdcpDevice *self,
|
||||
GBytes *nonce);
|
||||
void fpi_sdcp_device_identify_retry (FpSdcpDevice *self,
|
||||
GError *error);
|
||||
void fpi_sdcp_device_identify_complete (FpSdcpDevice *self,
|
||||
GBytes *id,
|
||||
GBytes *mac,
|
||||
GError *error);
|
||||
|
||||
void fpi_sdcp_device_get_print_id (FpPrint *print,
|
||||
GBytes **id);
|
||||
void fpi_sdcp_device_set_print_id (FpPrint *print,
|
||||
GBytes *id);
|
||||
1079
libfprint/fpi-sdcp.c
1079
libfprint/fpi-sdcp.c
File diff suppressed because it is too large
Load Diff
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Secure Device Connection Protocol (SDCP) support implementation
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fpi-compat.h"
|
||||
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
/**
|
||||
* fpi_sdcp_generate_host_key:
|
||||
* @private_key: (out) (transfer full): The host private key (sk_h)
|
||||
* @public_key: (out) (transfer full): The host public key (pk_h)
|
||||
* @error: (out): #GError in case the out values are %NULL
|
||||
*
|
||||
* Function to generate a new ephemeral ECDH key pair for use with SDCP.
|
||||
**/
|
||||
void fpi_sdcp_generate_host_key (GBytes **private_key,
|
||||
GBytes **public_key,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_generate_random:
|
||||
* @error: (out): #GError in case the return value is %NULL
|
||||
*
|
||||
* Returns: A new #GBytes with a secure random of length %SDCP_RANDOM_SIZE
|
||||
**/
|
||||
GBytes *fpi_sdcp_generate_random (GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_verify_connect:
|
||||
* @host_private_key: Private key generated using fpi_sdcp_generate_host_key() (sk_h)
|
||||
* @host_random: Random generated using fpi_sdcp_generate_random() (r_h)
|
||||
* @device_random: The random provided in the device's ConnectResponse (r_d)
|
||||
* @claim: #FpiSdcpClaim provided in the device's ConnectResponse (c)
|
||||
* @mac: The MAC provided in the device's ConnectResponse (m)
|
||||
* @validate_certificate: If the model certificate (cert_m) should be parsed and
|
||||
* its trust chain validated as issued from Microsoft's well-known issuers
|
||||
* @verify_signatures: If the model signature (s_m) and device signature (s_d)
|
||||
* should be validated against the certificate and keys provided in the claim
|
||||
* @application_secret: (out) (transfer full): A new #GBytes with the derived
|
||||
* application secret (s) of length %SDCP_APPLICATION_SECRET_SIZE
|
||||
* @error: (out): #GError in case the return value is %NULL
|
||||
*
|
||||
* High level function which internally handles the derivation of all necessary
|
||||
* SDCP-related keys and secrets from the device's ConnectResponse and derives
|
||||
* the application secret for use with all other SDCP-related functions.
|
||||
*
|
||||
* This function will also perform a validation of the ConnectResponse MAC and
|
||||
* optionally perform additional verifications based on the provided
|
||||
* @validate_certificate and @verify_signatures booleans. If any of these these
|
||||
* validations fail then %NULL will be returned, indicating that the SDCP secure
|
||||
* connection channel could not be established.
|
||||
*
|
||||
* Returns: %TRUE if the @application_secret was successfully derived and the
|
||||
* ConnectResponse has been successfully verified
|
||||
**/
|
||||
gboolean fpi_sdcp_verify_connect (GBytes *host_private_key,
|
||||
GBytes *host_random,
|
||||
GBytes *device_random,
|
||||
FpiSdcpClaim *claim,
|
||||
GBytes *mac,
|
||||
gboolean validate_certificate,
|
||||
gboolean verify_signatures,
|
||||
GBytes **application_secret,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_verify_reconnect:
|
||||
* @application_secret: The host's derived application secret (s)
|
||||
* @random: The host-generated random sent to the device's Reconnect command (r)
|
||||
* @mac: The MAC provided in the device's ReconnectResponse (m)
|
||||
* @error: (out): #GError in case the return value is %FALSE
|
||||
*
|
||||
* Verifies the SDCP ReconnectResponse.
|
||||
*
|
||||
* Returns: %TRUE if the ReconnectResponse is verified successfully
|
||||
**/
|
||||
gboolean fpi_sdcp_verify_reconnect (GBytes *application_secret,
|
||||
GBytes *random,
|
||||
GBytes *mac,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_verify_identify:
|
||||
* @application_secret: The host's derived application secret (s)
|
||||
* @nonce: The host-generated nonce sent to the device's Identify command (n)
|
||||
* @id: The ID provided in the device's AuthorizedIdentity (id)
|
||||
* @mac: The MAC provided in the device's AuthorizedIdentity (m)
|
||||
* @error: (out): #GError in case the return value is %FALSE
|
||||
*
|
||||
* Verifies the SDCP ReconnectResponse.
|
||||
*
|
||||
* Returns: %TRUE if the ReconnectResponse is verified successfully
|
||||
**/
|
||||
gboolean fpi_sdcp_verify_identify (GBytes *application_secret,
|
||||
GBytes *nonce,
|
||||
GBytes *id,
|
||||
GBytes *mac,
|
||||
GError **error);
|
||||
|
||||
/**
|
||||
* fpi_sdcp_generate_enrollment_id:
|
||||
* @application_secret: The host's derived application secret (s)
|
||||
* @nonce: The nonce received from the device in response to the EnrollBegin
|
||||
* command (n)
|
||||
* @error: (out): #GError in case the return value is %NULL
|
||||
*
|
||||
* Generates a new id for use with the device's EnrollCommit command.
|
||||
*
|
||||
* Returns: A new #GBytes with the generated enrollment id of length
|
||||
* %SDCP_ENROLLMENT_ID_SIZE
|
||||
**/
|
||||
GBytes *fpi_sdcp_generate_enrollment_id (GBytes *application_secret,
|
||||
GBytes *nonce,
|
||||
GError **error);
|
||||
@@ -21,7 +21,6 @@ libfprint_private_sources = [
|
||||
'fpi-device.c',
|
||||
'fpi-image-device.c',
|
||||
'fpi-image.c',
|
||||
'fpi-log.c',
|
||||
'fpi-print.c',
|
||||
'fpi-ssm.c',
|
||||
'fpi-usb-transfer.c',
|
||||
@@ -48,8 +47,8 @@ libfprint_private_headers = [
|
||||
'fpi-log.h',
|
||||
'fpi-minutiae.h',
|
||||
'fpi-print.h',
|
||||
'fpi-ssm.h',
|
||||
'fpi-usb-transfer.h',
|
||||
'fpi-ssm.h',
|
||||
] + spi_headers
|
||||
|
||||
nbis_sources = [
|
||||
@@ -144,8 +143,6 @@ driver_sources = {
|
||||
[ 'drivers/virtual-device.c' ],
|
||||
'virtual_device_storage' :
|
||||
[ 'drivers/virtual-device-storage.c' ],
|
||||
'virtual_sdcp' :
|
||||
[ 'drivers/virtual-sdcp.c' ],
|
||||
'synaptics' :
|
||||
[ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ],
|
||||
'goodixmoc' :
|
||||
@@ -167,8 +164,6 @@ helper_sources = {
|
||||
[ 'drivers/aes3k.c' ],
|
||||
'openssl' :
|
||||
[ ],
|
||||
'sdcp' :
|
||||
[ ],
|
||||
'udev' :
|
||||
[ ],
|
||||
'virtual' :
|
||||
@@ -184,24 +179,6 @@ foreach helper : driver_helpers
|
||||
drivers_sources += helper_sources[helper]
|
||||
endforeach
|
||||
|
||||
subdir('sdcp')
|
||||
if 'sdcp' in driver_helpers
|
||||
libfprint_sources += [
|
||||
'fp-sdcp-device.c',
|
||||
]
|
||||
libfprint_private_sources += [
|
||||
'fpi-sdcp.c',
|
||||
'fpi-sdcp-device.c',
|
||||
sdcp_truststore_resource_c,
|
||||
]
|
||||
libfprint_public_headers += [
|
||||
'fp-sdcp-device.h',
|
||||
]
|
||||
libfprint_private_headers += [
|
||||
'fpi-sdcp.h',
|
||||
'fpi-sdcp-device.h',
|
||||
]
|
||||
endif
|
||||
|
||||
fp_enums = gnome.mkenums_simple('fp-enums',
|
||||
sources: libfprint_public_headers,
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print("generate-gresource.py: Generates SDCP Truststore GResource XML file from certificates in ./truststore/*.pem")
|
||||
print("Usage: generate-gresource.py <libfprint_sdcp_source_dir> <output_xml_file>")
|
||||
sys.exit(1)
|
||||
|
||||
gresource_prefix = "/org/freedesktop/fprint/sdcp"
|
||||
relative_folder = "truststore"
|
||||
full_folder = os.path.join(sys.argv[1], relative_folder)
|
||||
output = sys.argv[2]
|
||||
|
||||
files = [f for f in os.listdir(full_folder) if os.path.isfile(os.path.join(full_folder, f)) and f.endswith('.pem')]
|
||||
|
||||
with open(output, 'w') as f:
|
||||
f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
|
||||
f.write('<gresources>\n')
|
||||
f.write(f' <gresource prefix="{gresource_prefix}">\n')
|
||||
for file in files:
|
||||
f.write(f' <file compressed="true">{relative_folder}/{file}</file>\n')
|
||||
f.write(' </gresource>\n')
|
||||
f.write('</gresources>\n')
|
||||
@@ -1,32 +0,0 @@
|
||||
sdcp_truststore_gresource_xml = custom_target('sdcp-truststore.gresource',
|
||||
input : 'generate-gresource.py',
|
||||
output : 'sdcp-truststore.gresource.xml',
|
||||
command : [find_program('python3'), '@INPUT@', meson.current_source_dir(), '@OUTPUT@'],
|
||||
)
|
||||
|
||||
sdcp_truststore_resource_h = custom_target('fpi-sdcp-truststore-resource.h',
|
||||
input : sdcp_truststore_gresource_xml,
|
||||
output : 'fpi-sdcp-truststore-resource.h',
|
||||
command : ['glib-compile-resources',
|
||||
'--target=@OUTPUT@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
'--internal',
|
||||
'--generate',
|
||||
'--c-name', 'fpi_sdcp_truststore',
|
||||
'--manual-register',
|
||||
'@INPUT@']
|
||||
)
|
||||
|
||||
sdcp_truststore_resource_c = custom_target('fpi-sdcp-truststore-resource.c',
|
||||
depends : [sdcp_truststore_resource_h],
|
||||
input : sdcp_truststore_gresource_xml,
|
||||
output : 'fpi-sdcp-truststore-resource.c',
|
||||
command : ['glib-compile-resources',
|
||||
'--target=@OUTPUT@',
|
||||
'--sourcedir=' + meson.current_source_dir(),
|
||||
'--internal',
|
||||
'--generate',
|
||||
'--c-name', 'fpi_sdcp_truststore',
|
||||
'--manual-register',
|
||||
'@INPUT@']
|
||||
)
|
||||
@@ -1,19 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDIDCCAqWgAwIBAgIQKs9yK9kUXqlMVB+fSF1UMjAKBggqhkjOPQQDAzCBlDEL
|
||||
MAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1v
|
||||
bmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE+MDwGA1UEAxM1TWlj
|
||||
cm9zb2Z0IEVDQyBEZXZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw
|
||||
MTcwHhcNMTcxMTA5MTk0MDQ4WhcNNDIxMTA5MTk0ODE5WjCBlDELMAkGA1UEBhMC
|
||||
VVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAcBgNV
|
||||
BAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE+MDwGA1UEAxM1TWljcm9zb2Z0IEVD
|
||||
QyBEZXZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq
|
||||
hkjOPQIBBgUrgQQAIgNiAARiivDX0DS0EXoGlfbd2PwxSC87Cszr6/aAjSx6pMwU
|
||||
4kzXcId0dhrjSkPSIO5UCz50ggQGQiTwqRzyhM44FlEyzbzl6OHGDwR1vAg3wdmm
|
||||
WEXWySzyAZKsfkwg0G7bPkijgbkwgbYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wHQYDVR0OBBYEFBTaW/EOZkfRXRNfW3rr618BCLVJMBAGCSsGAQQBgjcV
|
||||
AQQDAgEAMGUGA1UdIAReMFwwBgYEVR0gADBSBgwrBgEEAYI3TIN9AQEwQjBABggr
|
||||
BgEFBQcCARY0aHR0cDovL3d3dy5taWNyb3NvZnQuY29tL3BraW9wcy9Eb2NzL1Jl
|
||||
cG9zaXRvcnkuaHRtADAKBggqhkjOPQQDAwNpADBmAjEAxxAFFL8juLXiulXvZgBQ
|
||||
pGGPCcV2Tr3CorZ4p/uO2/rtBemqhL3CjKAm40VlhEz8AjEArE5fhA54SEDjoTwZ
|
||||
VUosaqXa8ych31qjZI+e1ttbOPebAZTt9ac7+lTzJcLTEQch
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,23 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDwzCCA0qgAwIBAgITMwAAAAuNaMBkOddK4wAAAAAACzAKBggqhkjOPQQDAjCB
|
||||
hDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
|
||||
ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEuMCwGA1UEAxMl
|
||||
V2luZG93cyBIZWxsbyBTZWN1cmUgRGV2aWNlcyBQQ0EgMjAxODAeFw0yMTEyMDky
|
||||
MzI1MDFaFw0zMDEyMDkyMzM1MDFaMFYxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVN
|
||||
aWNyb3NvZnQgQ29ycG9yYXRpb24xJzAlBgNVBAMTHldpbmRvd3MgSGVsbG8gMjA5
|
||||
NkFEQ0MgQ0EgMjAyMTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJWgPvl44Gei
|
||||
RrTuA3f1eT60pAlBWM7ym7WSchqz3hge1WS8RUxPVedu0f7MCe/R6O6RVjV7HWq4
|
||||
c6jo9FwoiAGjggHGMIIBwjAQBgkrBgEEAYI3FQEEAwIBADAdBgNVHQ4EFgQUvzdI
|
||||
40pjLelTo7qJApjAaUcqmbkwVAYDVR0gBE0wSzBJBgRVHSAAMEEwPwYIKwYBBQUH
|
||||
AgEWM2h0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMvRG9jcy9SZXBvc2l0
|
||||
b3J5Lmh0bTAZBgkrBgEEAYI3FAIEDB4KAFMAdQBiAEMAQTALBgNVHQ8EBAMCAYYw
|
||||
DwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBTaykvQTFYDJ1+X63WjAsO/RZz4
|
||||
sTBoBgNVHR8EYTBfMF2gW6BZhldodHRwOi8vd3d3Lm1pY3Jvc29mdC5jb20vcGtp
|
||||
b3BzL2NybC9XaW5kb3dzJTIwSGVsbG8lMjBTZWN1cmUlMjBEZXZpY2VzJTIwUENB
|
||||
JTIwMjAxOC5jcmwwdQYIKwYBBQUHAQEEaTBnMGUGCCsGAQUFBzAChllodHRwOi8v
|
||||
d3d3Lm1pY3Jvc29mdC5jb20vcGtpb3BzL2NlcnRzL1dpbmRvd3MlMjBIZWxsbyUy
|
||||
MFNlY3VyZSUyMERldmljZXMlMjBQQ0ElMjAyMDE4LmNydDAKBggqhkjOPQQDAgNn
|
||||
ADBkAjAeGyYlzf+uBQXI/EW84I5CGFbo/U6dL4k1Y83f2p94d0wrNwjUb/yprb4+
|
||||
L9+OKfQCME8PgRyJQxsvsne+WI6gr0ZzJilotoiRdvDzlMK4+hx5TGJWTV17AsAo
|
||||
z2330epHQQ==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,26 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEVjCCA9ygAwIBAgITMwAAAANsz+3iRHAZvwAAAAAAAzAKBggqhkjOPQQDAzCB
|
||||
lDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1Jl
|
||||
ZG1vbmQxHjAcBgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjE+MDwGA1UEAxM1
|
||||
TWljcm9zb2Z0IEVDQyBEZXZpY2VzIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
|
||||
IDIwMTcwHhcNMTgwMTI1MTk0OTM4WhcNMzMwMTI1MTk1OTM4WjCBhDELMAkGA1UE
|
||||
BhMCVVMxEzARBgNVBAgTCldhc2hpbmd0b24xEDAOBgNVBAcTB1JlZG1vbmQxHjAc
|
||||
BgNVBAoTFU1pY3Jvc29mdCBDb3Jwb3JhdGlvbjEuMCwGA1UEAxMlV2luZG93cyBI
|
||||
ZWxsbyBTZWN1cmUgRGV2aWNlcyBQQ0EgMjAxODB2MBAGByqGSM49AgEGBSuBBAAi
|
||||
A2IABB3dCAIDJXUg4nGLrSgJgukG7oPFOmxLcZJQTiDpcrT8UyrvXcyatM12uJSX
|
||||
RLJxDsmxFgOhZSu56F1f8jAu3bErIPy+AIjqH6d/mYSYfHE+TTSDaZsIy3iyS73X
|
||||
Pr5noKOCAfwwggH4MBAGCSsGAQQBgjcVAQQDAgEAMB0GA1UdDgQWBBTaykvQTFYD
|
||||
J1+X63WjAsO/RZz4sTBlBgNVHSAEXjBcMAYGBFUdIAAwUgYMKwYBBAGCN0yDfQEB
|
||||
MEIwQAYIKwYBBQUHAgEWNGh0dHA6Ly93d3cubWljcm9zb2Z0LmNvbS9wa2lvcHMv
|
||||
RG9jcy9SZXBvc2l0b3J5Lmh0bQAwGQYJKwYBBAGCNxQCBAweCgBTAHUAYgBDAEEw
|
||||
CwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUFNpb8Q5m
|
||||
R9FdE19beuvrXwEItUkwegYDVR0fBHMwcTBvoG2ga4ZpaHR0cDovL3d3dy5taWNy
|
||||
b3NvZnQuY29tL3BraW9wcy9jcmwvTWljcm9zb2Z0JTIwRUNDJTIwRGV2aWNlcyUy
|
||||
MFJvb3QlMjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMTcuY3JsMIGHBggr
|
||||
BgEFBQcBAQR7MHkwdwYIKwYBBQUHMAKGa2h0dHA6Ly93d3cubWljcm9zb2Z0LmNv
|
||||
bS9wa2lvcHMvY2VydHMvTWljcm9zb2Z0JTIwRUNDJTIwRGV2aWNlcyUyMFJvb3Ql
|
||||
MjBDZXJ0aWZpY2F0ZSUyMEF1dGhvcml0eSUyMDIwMTcuY3J0MAoGCCqGSM49BAMD
|
||||
A2gAMGUCMFYqrXJMuYyzI4D1X/ghlGYPdnfiewPdMF7LkMp45gstEuX3ZzFYcebz
|
||||
ZMEEs4vp4gIxALkgYbnQXjqkoor+HfwnYQuYFowCnCB/7vPLHwo3YrGOztmanqzm
|
||||
GtS48agrsbRAmw==
|
||||
-----END CERTIFICATE-----
|
||||
13
meson.build
13
meson.build
@@ -112,8 +112,8 @@ virtual_drivers = [
|
||||
'virtual_image',
|
||||
'virtual_device',
|
||||
'virtual_device_storage',
|
||||
'virtual_sdcp',
|
||||
]
|
||||
|
||||
default_drivers = [
|
||||
'upektc_img',
|
||||
'vfs5011',
|
||||
@@ -209,13 +209,11 @@ driver_helper_mapping = {
|
||||
'aes2660' : [ 'aeslib', 'aesx660' ],
|
||||
'aes3500' : [ 'aeslib', 'aes3k' ],
|
||||
'aes4000' : [ 'aeslib', 'aes3k' ],
|
||||
'egismoc' : [ 'sdcp' ],
|
||||
'elanspi' : [ 'udev' ],
|
||||
'uru4000' : [ 'openssl' ],
|
||||
'elanspi' : [ 'udev' ],
|
||||
'virtual_image' : [ 'virtual' ],
|
||||
'virtual_device' : [ 'virtual' ],
|
||||
'virtual_device_storage' : [ 'virtual' ],
|
||||
'virtual_sdcp' : [ 'virtual', 'sdcp' ],
|
||||
}
|
||||
|
||||
driver_helpers = []
|
||||
@@ -274,13 +272,6 @@ foreach i : driver_helpers
|
||||
error('OpenSSL is required for @0@ and possibly others'.format(driver))
|
||||
endif
|
||||
|
||||
optional_deps += openssl_dep
|
||||
elif i == 'sdcp'
|
||||
openssl_dep = dependency('openssl', version: '>= 3.0.8', required: false)
|
||||
if not openssl_dep.found()
|
||||
error('OpenSSL >= 3.0.8 is required for SDCP support (@0@ and possibly others)'.format(driver))
|
||||
endif
|
||||
|
||||
optional_deps += openssl_dep
|
||||
elif i == 'udev'
|
||||
install_udev_rules = true
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 100 KiB After Width: | Height: | Size: 41 KiB |
@@ -1,30 +1,44 @@
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb1/1-9
|
||||
N: bus/usb/001/005=12011001000000087A1C700541100102030109022000010100A0320904000002FF0000000705830240000007050402400003
|
||||
E: DEVNAME=/dev/bus/usb/001/005
|
||||
N: bus/usb/001/013=12011001000000087A1C700541100102030109022000010100A0320904000002FF0000000705830240000007050402400003
|
||||
E: BUSNUM=001
|
||||
E: CURRENT_TAGS=:seat:
|
||||
E: DEVNAME=/dev/bus/usb/001/013
|
||||
E: DEVNUM=013
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: PRODUCT=1c7a/570/1041
|
||||
E: TYPE=0/0/0
|
||||
E: BUSNUM=001
|
||||
E: DEVNUM=005
|
||||
E: MAJOR=189
|
||||
E: MINOR=4
|
||||
E: SUBSYSTEM=usb
|
||||
E: ID_VENDOR=EgisTec
|
||||
E: ID_VENDOR_ENC=EgisTec
|
||||
E: ID_VENDOR_ID=1c7a
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_BUS=usb
|
||||
E: ID_FOR_SEAT=usb-pci-0000_00_14_0-usb-0_9
|
||||
E: ID_MODEL=EgisTec_Touch_Fingerprint_Sensor
|
||||
E: ID_MODEL_ENC=EgisTec\x20Touch\x20Fingerprint\x20Sensor
|
||||
E: ID_MODEL_ID=0570
|
||||
E: ID_REVISION=1041
|
||||
E: ID_SERIAL=EgisTec_EgisTec_Touch_Fingerprint_Sensor_W700B41B
|
||||
E: ID_SERIAL_SHORT=W700B41B
|
||||
E: ID_BUS=usb
|
||||
E: ID_USB_INTERFACES=:ff0000:
|
||||
E: ID_VENDOR_FROM_DATABASE=LighTuning Technology Inc.
|
||||
E: ID_PATH=pci-0000:00:14.0-usb-0:9
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_9
|
||||
E: LIBFPRINT_DRIVER=Hardcoded allowlist
|
||||
E: ID_PATH_WITH_USB_REVISION=pci-0000:00:14.0-usbv2-0:9
|
||||
E: ID_PERSIST=0
|
||||
E: ID_REVISION=1041
|
||||
E: ID_SERIAL=EgisTec_EgisTec_Touch_Fingerprint_Sensor_0007989A
|
||||
E: ID_SERIAL_SHORT=0007989A
|
||||
E: ID_USB_INTERFACES=:ff0000:
|
||||
E: ID_USB_MODEL=EgisTec_Touch_Fingerprint_Sensor
|
||||
E: ID_USB_MODEL_ENC=EgisTec\x20Touch\x20Fingerprint\x20Sensor
|
||||
E: ID_USB_MODEL_ID=0570
|
||||
E: ID_USB_REVISION=1041
|
||||
E: ID_USB_SERIAL=EgisTec_EgisTec_Touch_Fingerprint_Sensor_0007989A
|
||||
E: ID_USB_SERIAL_SHORT=0007989A
|
||||
E: ID_USB_VENDOR=EgisTec
|
||||
E: ID_USB_VENDOR_ENC=EgisTec
|
||||
E: ID_USB_VENDOR_ID=1c7a
|
||||
E: ID_VENDOR=EgisTec
|
||||
E: ID_VENDOR_ENC=EgisTec
|
||||
E: ID_VENDOR_FROM_DATABASE=LighTuning Technology Inc.
|
||||
E: ID_VENDOR_ID=1c7a
|
||||
E: MAJOR=189
|
||||
E: MINOR=12
|
||||
E: PRODUCT=1c7a/570/1041
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:seat:
|
||||
E: TYPE=0/0/0
|
||||
A: authorized=1\n
|
||||
A: avoid_reset_quirk=0\n
|
||||
A: bConfigurationValue=1\n
|
||||
@@ -38,32 +52,34 @@ A: bNumInterfaces= 1\n
|
||||
A: bcdDevice=1041\n
|
||||
A: bmAttributes=a0\n
|
||||
A: busnum=1\n
|
||||
A: configuration=\n
|
||||
A: configuration=
|
||||
H: descriptors=12011001000000087A1C700541100102030109022000010100A0320904000002FF0000000705830240000007050402400003
|
||||
A: dev=189:4\n
|
||||
A: devnum=5\n
|
||||
A: dev=189:12\n
|
||||
A: devnum=13\n
|
||||
A: devpath=9\n
|
||||
L: driver=../../../../../bus/usb/drivers/usb
|
||||
L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1d/device:1e/device:28
|
||||
A: idProduct=0570\n
|
||||
A: idVendor=1c7a\n
|
||||
A: ltm_capable=no\n
|
||||
A: manufacturer=EgisTec\n
|
||||
A: maxchild=0\n
|
||||
A: physical_location/dock=no\n
|
||||
A: physical_location/horizontal_position=left\n
|
||||
A: physical_location/lid=no\n
|
||||
A: physical_location/panel=unknown\n
|
||||
A: physical_location/vertical_position=upper\n
|
||||
L: port=../1-0:1.0/usb1-port9
|
||||
A: power/active_duration=362352\n
|
||||
A: power/async=enabled\n
|
||||
A: power/active_duration=434262\n
|
||||
A: power/autosuspend=2\n
|
||||
A: power/autosuspend_delay_ms=2000\n
|
||||
A: power/connected_duration=5526124\n
|
||||
A: power/connected_duration=2971461\n
|
||||
A: power/control=auto\n
|
||||
A: power/level=auto\n
|
||||
A: power/persist=1\n
|
||||
A: power/runtime_active_kids=0\n
|
||||
A: power/runtime_active_time=365097\n
|
||||
A: power/runtime_enabled=enabled\n
|
||||
A: power/persist=0\n
|
||||
A: power/runtime_active_time=436346\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=5160752\n
|
||||
A: power/runtime_usage=0\n
|
||||
A: power/runtime_suspended_time=2534879\n
|
||||
A: power/wakeup=disabled\n
|
||||
A: power/wakeup_abort_count=\n
|
||||
A: power/wakeup_active=\n
|
||||
@@ -77,41 +93,52 @@ A: product=EgisTec Touch Fingerprint Sensor\n
|
||||
A: quirks=0x0\n
|
||||
A: removable=fixed\n
|
||||
A: rx_lanes=1\n
|
||||
A: serial=W700B41B\n
|
||||
A: serial=0007989A\n
|
||||
A: speed=12\n
|
||||
A: tx_lanes=1\n
|
||||
A: urbnum=8040\n
|
||||
A: urbnum=95937\n
|
||||
A: version= 1.10\n
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb1
|
||||
N: bus/usb/001/001=12010002090001406B1D020008050302010109021900010100E0000904000001090000000705810304000C
|
||||
N: bus/usb/001/001=12010002090001406B1D020017060302010109021900010100E0000904000001090000000705810304000C
|
||||
E: BUSNUM=001
|
||||
E: CURRENT_TAGS=:seat:
|
||||
E: DEVNAME=/dev/bus/usb/001/001
|
||||
E: DEVNUM=001
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: PRODUCT=1d6b/2/508
|
||||
E: TYPE=9/0/1
|
||||
E: BUSNUM=001
|
||||
E: DEVNUM=001
|
||||
E: MAJOR=189
|
||||
E: MINOR=0
|
||||
E: SUBSYSTEM=usb
|
||||
E: ID_VENDOR=Linux_5.8.0-59-generic_xhci-hcd
|
||||
E: ID_VENDOR_ENC=Linux\x205.8.0-59-generic\x20xhci-hcd
|
||||
E: ID_VENDOR_ID=1d6b
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_BUS=usb
|
||||
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
|
||||
E: ID_MODEL=xHCI_Host_Controller
|
||||
E: ID_MODEL_ENC=xHCI\x20Host\x20Controller
|
||||
E: ID_MODEL_ID=0002
|
||||
E: ID_REVISION=0508
|
||||
E: ID_SERIAL=Linux_5.8.0-59-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_BUS=usb
|
||||
E: ID_USB_INTERFACES=:090000:
|
||||
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
|
||||
E: ID_MODEL_FROM_DATABASE=2.0 root hub
|
||||
E: ID_MODEL_ID=0002
|
||||
E: ID_PATH=pci-0000:00:14.0
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0
|
||||
E: ID_FOR_SEAT=usb-pci-0000_00_14_0
|
||||
E: ID_REVISION=0617
|
||||
E: ID_SERIAL=Linux_6.17.5-arch1-1_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_USB_INTERFACES=:090000:
|
||||
E: ID_USB_MODEL=xHCI_Host_Controller
|
||||
E: ID_USB_MODEL_ENC=xHCI\x20Host\x20Controller
|
||||
E: ID_USB_MODEL_ID=0002
|
||||
E: ID_USB_REVISION=0617
|
||||
E: ID_USB_SERIAL=Linux_6.17.5-arch1-1_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_USB_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_USB_VENDOR=Linux_6.17.5-arch1-1_xhci-hcd
|
||||
E: ID_USB_VENDOR_ENC=Linux\x206.17.5-arch1-1\x20xhci-hcd
|
||||
E: ID_USB_VENDOR_ID=1d6b
|
||||
E: ID_VENDOR=Linux_6.17.5-arch1-1_xhci-hcd
|
||||
E: ID_VENDOR_ENC=Linux\x206.17.5-arch1-1\x20xhci-hcd
|
||||
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
|
||||
E: ID_VENDOR_ID=1d6b
|
||||
E: MAJOR=189
|
||||
E: MINOR=0
|
||||
E: PRODUCT=1d6b/2/617
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:seat:
|
||||
E: TYPE=9/0/1
|
||||
A: authorized=1\n
|
||||
A: authorized_default=1\n
|
||||
A: avoid_reset_quirk=0\n
|
||||
@@ -123,34 +150,31 @@ A: bMaxPacketSize0=64\n
|
||||
A: bMaxPower=0mA\n
|
||||
A: bNumConfigurations=1\n
|
||||
A: bNumInterfaces= 1\n
|
||||
A: bcdDevice=0508\n
|
||||
A: bcdDevice=0617\n
|
||||
A: bmAttributes=e0\n
|
||||
A: busnum=1\n
|
||||
A: configuration=\n
|
||||
H: descriptors=12010002090001406B1D020008050302010109021900010100E0000904000001090000000705810304000C
|
||||
A: configuration=
|
||||
H: descriptors=12010002090001406B1D020017060302010109021900010100E0000904000001090000000705810304000C
|
||||
A: dev=189:0\n
|
||||
A: devnum=1\n
|
||||
A: devpath=0\n
|
||||
L: driver=../../../../bus/usb/drivers/usb
|
||||
L: firmware_node=../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1d/device:1e
|
||||
A: idProduct=0002\n
|
||||
A: idVendor=1d6b\n
|
||||
A: interface_authorized_default=1\n
|
||||
A: ltm_capable=no\n
|
||||
A: manufacturer=Linux 5.8.0-59-generic xhci-hcd\n
|
||||
A: manufacturer=Linux 6.17.5-arch1-1 xhci-hcd\n
|
||||
A: maxchild=12\n
|
||||
A: power/active_duration=378024\n
|
||||
A: power/async=enabled\n
|
||||
A: power/active_duration=1253682\n
|
||||
A: power/autosuspend=0\n
|
||||
A: power/autosuspend_delay_ms=0\n
|
||||
A: power/connected_duration=5527220\n
|
||||
A: power/connected_duration=6204832\n
|
||||
A: power/control=auto\n
|
||||
A: power/level=auto\n
|
||||
A: power/runtime_active_kids=1\n
|
||||
A: power/runtime_active_time=377962\n
|
||||
A: power/runtime_enabled=enabled\n
|
||||
A: power/runtime_active_time=1253672\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=5149253\n
|
||||
A: power/runtime_usage=0\n
|
||||
A: power/runtime_suspended_time=4951157\n
|
||||
A: power/wakeup=disabled\n
|
||||
A: power/wakeup_abort_count=\n
|
||||
A: power/wakeup_active=\n
|
||||
@@ -167,62 +191,72 @@ A: rx_lanes=1\n
|
||||
A: serial=0000:00:14.0\n
|
||||
A: speed=480\n
|
||||
A: tx_lanes=1\n
|
||||
A: urbnum=956\n
|
||||
A: urbnum=2401\n
|
||||
A: version= 2.00\n
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0
|
||||
E: DRIVER=xhci_hcd
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller
|
||||
E: ID_PATH=pci-0000:00:14.0
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
|
||||
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
|
||||
E: MODALIAS=pci:v00008086d00009D2Fsv00001025sd0000118Cbc0Csc03i30
|
||||
E: PCI_CLASS=C0330
|
||||
E: PCI_ID=8086:9D2F
|
||||
E: PCI_SUBSYS_ID=1025:118E
|
||||
E: PCI_SLOT_NAME=0000:00:14.0
|
||||
E: MODALIAS=pci:v00008086d00009D2Fsv00001025sd0000118Ebc0Csc03i30
|
||||
E: PCI_SUBSYS_ID=1025:118C
|
||||
E: SUBSYSTEM=pci
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
|
||||
E: ID_VENDOR_FROM_DATABASE=Intel Corporation
|
||||
E: ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller
|
||||
A: ari_enabled=0\n
|
||||
A: broken_parity_status=0\n
|
||||
A: class=0x0c0330\n
|
||||
H: config=86802F9D060490022130030C00008000040021A400000000000000000000000000000000000000000000000025108E11000000007000000000000000FF010000
|
||||
H: config=86802F9D060490022130030C00008000040011B100000000000000000000000000000000000000000000000025108C11000000007000000000000000FF010000FD01348088C60F8000000000000000005B6ECE0F000000000000000000000000306000000000000000000000000000000180C2C10800000000000000000000000500B7001803E0FE0000000000000000090014F01000400100000000C10A080000080000001800008F400200000104000100000002000000100000000C000000000000000000000000000000000000000100000002000000000000000C000000000000000000000000000000000000000000000000000000B30F410800000000
|
||||
A: consistent_dma_mask_bits=64\n
|
||||
A: d3cold_allowed=1\n
|
||||
A: dbc=disabled\n
|
||||
A: dbc_bInterfaceProtocol=01\n
|
||||
A: dbc_bcdDevice=0010\n
|
||||
A: dbc_idProduct=0010\n
|
||||
A: dbc_idVendor=1d6b\n
|
||||
A: dbc_poll_interval_ms=64\n
|
||||
A: device=0x9d2f\n
|
||||
A: dma_mask_bits=64\n
|
||||
L: driver=../../../bus/pci/drivers/xhci_hcd
|
||||
A: driver_override=(null)\n
|
||||
A: enable=1\n
|
||||
A: irq=127\n
|
||||
A: local_cpulist=0-7\n
|
||||
A: local_cpus=ff\n
|
||||
A: modalias=pci:v00008086d00009D2Fsv00001025sd0000118Ebc0Csc03i30\n
|
||||
L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1d
|
||||
A: irq=123\n
|
||||
A: local_cpulist=0-3\n
|
||||
A: local_cpus=f\n
|
||||
A: modalias=pci:v00008086d00009D2Fsv00001025sd0000118Cbc0Csc03i30\n
|
||||
A: msi_bus=1\n
|
||||
A: msi_irqs/123=msi\n
|
||||
A: msi_irqs/124=msi\n
|
||||
A: msi_irqs/125=msi\n
|
||||
A: msi_irqs/126=msi\n
|
||||
A: msi_irqs/127=msi\n
|
||||
A: numa_node=-1\n
|
||||
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 9 10 2112 10\nxHCI ring segments 32 36 4096 36\nbuffer-2048 1 2 2048 1\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\n
|
||||
A: power/async=enabled\n
|
||||
A: power/control=on\n
|
||||
A: power/runtime_active_kids=1\n
|
||||
A: power/runtime_active_time=5524703\n
|
||||
A: power/runtime_enabled=forbidden\n
|
||||
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 256 port bw ctx arrays 0 0 256 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 8 9 2112 9\nxHCI ring segments 33 33 4096 33\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\n
|
||||
A: power/control=auto\n
|
||||
A: power/runtime_active_time=1256085\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=3373\n
|
||||
A: power/runtime_usage=1\n
|
||||
A: power/runtime_suspended_time=4949020\n
|
||||
A: power/wakeup=enabled\n
|
||||
A: power/wakeup_abort_count=0\n
|
||||
A: power/wakeup_active=0\n
|
||||
A: power/wakeup_active_count=0\n
|
||||
A: power/wakeup_active_count=7\n
|
||||
A: power/wakeup_count=0\n
|
||||
A: power/wakeup_expire_count=0\n
|
||||
A: power/wakeup_last_time_ms=0\n
|
||||
A: power/wakeup_max_time_ms=0\n
|
||||
A: power/wakeup_total_time_ms=0\n
|
||||
A: resource=0x00000000a4210000 0x00000000a421ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n
|
||||
A: power/wakeup_expire_count=7\n
|
||||
A: power/wakeup_last_time_ms=3233739\n
|
||||
A: power/wakeup_max_time_ms=108\n
|
||||
A: power/wakeup_total_time_ms=736\n
|
||||
A: power_state=D0\n
|
||||
A: resource=0x00000000b1110000 0x00000000b111ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n
|
||||
A: revision=0x21\n
|
||||
A: subsystem_device=0x118e\n
|
||||
A: subsystem_device=0x118c\n
|
||||
A: subsystem_vendor=0x1025\n
|
||||
A: vendor=0x8086\n
|
||||
|
||||
|
||||
Binary file not shown.
@@ -1,21 +1,17 @@
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb3/3-5
|
||||
N: bus/usb/003/002=12010002FF0000407A1C820581110102030109022700010100A0320904000003FF000000070581020002000705020200020007058303400005
|
||||
N: bus/usb/003/012=12010002FF0000407A1C820581110102030109022700010100A0320904000003FF000000070581020002000705020200020007058303400005
|
||||
E: BUSNUM=003
|
||||
E: CURRENT_TAGS=:snap_cups_ippeveprinter:snap_android-platform-tools_fastboot:snap_android-platform-tools_adb:snap_cups_cupsd:
|
||||
E: DEVNAME=/dev/bus/usb/003/002
|
||||
E: DEVNUM=002
|
||||
E: CURRENT_TAGS=:snap_cups_ippeveprinter:snap_cups_cupsd:
|
||||
E: DEVNAME=/dev/bus/usb/003/012
|
||||
E: DEVNUM=012
|
||||
E: DEVTYPE=usb_device
|
||||
E: DRIVER=usb
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_BUS=usb
|
||||
E: ID_MODEL=ETU905A80-E
|
||||
E: ID_MODEL_ENC=ETU905A80-E
|
||||
E: ID_MODEL_ID=0582
|
||||
E: ID_PATH=pci-0000:00:14.0-usb-0:5
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0-usb-0_5
|
||||
E: ID_PATH_WITH_USB_REVISION=pci-0000:00:14.0-usbv2-0:5
|
||||
E: ID_PERSIST=0
|
||||
E: ID_PROCESSING=1
|
||||
E: ID_REVISION=1181
|
||||
E: ID_SERIAL=EGIS_ETU905A80-E_0E7828PBS393
|
||||
E: ID_SERIAL_SHORT=0E7828PBS393
|
||||
@@ -34,10 +30,10 @@ E: ID_VENDOR_ENC=EGIS
|
||||
E: ID_VENDOR_FROM_DATABASE=LighTuning Technology Inc.
|
||||
E: ID_VENDOR_ID=1c7a
|
||||
E: MAJOR=189
|
||||
E: MINOR=257
|
||||
E: MINOR=267
|
||||
E: PRODUCT=1c7a/582/1181
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:snap_cups_ippeveprinter:snap_android-platform-tools_fastboot:snap_cups_cupsd:snap_android-platform-tools_adb:
|
||||
E: TAGS=:snap_cups_ippeveprinter:snap_cups_cupsd:
|
||||
E: TYPE=255/0/0
|
||||
A: authorized=1\n
|
||||
A: avoid_reset_quirk=0\n
|
||||
@@ -54,8 +50,8 @@ A: bmAttributes=a0\n
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002FF0000407A1C820581110102030109022700010100A0320904000003FF000000070581020002000705020200020007058303400005
|
||||
A: dev=189:257\n
|
||||
A: devnum=2\n
|
||||
A: dev=189:267\n
|
||||
A: devnum=12\n
|
||||
A: devpath=5\n
|
||||
L: driver=../../../../../bus/usb/drivers/usb
|
||||
L: firmware_node=../../../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:51/device:52/device:57
|
||||
@@ -70,20 +66,20 @@ A: physical_location/lid=no\n
|
||||
A: physical_location/panel=unknown\n
|
||||
A: physical_location/vertical_position=center\n
|
||||
L: port=../3-0:1.0/usb3-port5
|
||||
A: power/active_duration=2329204\n
|
||||
A: power/active_duration=1425996\n
|
||||
A: power/async=enabled\n
|
||||
A: power/autosuspend=2\n
|
||||
A: power/autosuspend_delay_ms=2000\n
|
||||
A: power/connected_duration=96447632\n
|
||||
A: power/control=auto\n
|
||||
A: power/level=auto\n
|
||||
A: power/persist=1\n
|
||||
A: power/connected_duration=1426656\n
|
||||
A: power/control=on\n
|
||||
A: power/level=on\n
|
||||
A: power/persist=0\n
|
||||
A: power/runtime_active_kids=0\n
|
||||
A: power/runtime_active_time=2345067\n
|
||||
A: power/runtime_enabled=enabled\n
|
||||
A: power/runtime_active_time=1426124\n
|
||||
A: power/runtime_enabled=forbidden\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=94056717\n
|
||||
A: power/runtime_usage=0\n
|
||||
A: power/runtime_suspended_time=0\n
|
||||
A: power/runtime_usage=1\n
|
||||
A: power/wakeup=disabled\n
|
||||
A: power/wakeup_abort_count=\n
|
||||
A: power/wakeup_active=\n
|
||||
@@ -100,13 +96,13 @@ A: rx_lanes=1\n
|
||||
A: serial=0E7828PBS393\n
|
||||
A: speed=480\n
|
||||
A: tx_lanes=1\n
|
||||
A: urbnum=10257\n
|
||||
A: urbnum=2803\n
|
||||
A: version= 2.00\n
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0/usb3
|
||||
N: bus/usb/003/001=12010002090001406B1D020015060302010109021900010100E0000904000001090000000705810304000C
|
||||
N: bus/usb/003/001=12010002090001406B1D020002060302010109021900010100E0000904000001090000000705810304000C
|
||||
E: BUSNUM=003
|
||||
E: CURRENT_TAGS=:snap_cups_ippeveprinter:seat:snap_android-platform-tools_fastboot:snap_cups_cupsd:snap_android-platform-tools_adb:
|
||||
E: CURRENT_TAGS=:seat:snap_cups_cupsd:snap_cups_ippeveprinter:
|
||||
E: DEVNAME=/dev/bus/usb/003/001
|
||||
E: DEVNUM=001
|
||||
E: DEVTYPE=usb_device
|
||||
@@ -120,28 +116,28 @@ E: ID_MODEL_FROM_DATABASE=2.0 root hub
|
||||
E: ID_MODEL_ID=0002
|
||||
E: ID_PATH=pci-0000:00:14.0
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0
|
||||
E: ID_REVISION=0615
|
||||
E: ID_SERIAL=Linux_6.15.1_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_REVISION=0602
|
||||
E: ID_SERIAL=Linux_6.2.0-34-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_USB_INTERFACES=:090000:
|
||||
E: ID_USB_MODEL=xHCI_Host_Controller
|
||||
E: ID_USB_MODEL_ENC=xHCI\x20Host\x20Controller
|
||||
E: ID_USB_MODEL_ID=0002
|
||||
E: ID_USB_REVISION=0615
|
||||
E: ID_USB_SERIAL=Linux_6.15.1_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_USB_REVISION=0602
|
||||
E: ID_USB_SERIAL=Linux_6.2.0-34-generic_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
|
||||
E: ID_USB_SERIAL_SHORT=0000:00:14.0
|
||||
E: ID_USB_VENDOR=Linux_6.15.1_xhci-hcd
|
||||
E: ID_USB_VENDOR_ENC=Linux\x206.15.1\x20xhci-hcd
|
||||
E: ID_USB_VENDOR=Linux_6.2.0-34-generic_xhci-hcd
|
||||
E: ID_USB_VENDOR_ENC=Linux\x206.2.0-34-generic\x20xhci-hcd
|
||||
E: ID_USB_VENDOR_ID=1d6b
|
||||
E: ID_VENDOR=Linux_6.15.1_xhci-hcd
|
||||
E: ID_VENDOR_ENC=Linux\x206.15.1\x20xhci-hcd
|
||||
E: ID_VENDOR=Linux_6.2.0-34-generic_xhci-hcd
|
||||
E: ID_VENDOR_ENC=Linux\x206.2.0-34-generic\x20xhci-hcd
|
||||
E: ID_VENDOR_FROM_DATABASE=Linux Foundation
|
||||
E: ID_VENDOR_ID=1d6b
|
||||
E: MAJOR=189
|
||||
E: MINOR=256
|
||||
E: PRODUCT=1d6b/2/615
|
||||
E: PRODUCT=1d6b/2/602
|
||||
E: SUBSYSTEM=usb
|
||||
E: TAGS=:snap_cups_ippeveprinter:seat:snap_android-platform-tools_fastboot:snap_cups_cupsd:snap_android-platform-tools_adb:
|
||||
E: TAGS=:snap_cups_cupsd:seat:snap_cups_ippeveprinter:
|
||||
E: TYPE=9/0/1
|
||||
A: authorized=1\n
|
||||
A: authorized_default=1\n
|
||||
@@ -154,11 +150,11 @@ A: bMaxPacketSize0=64\n
|
||||
A: bMaxPower=0mA\n
|
||||
A: bNumConfigurations=1\n
|
||||
A: bNumInterfaces= 1\n
|
||||
A: bcdDevice=0615\n
|
||||
A: bcdDevice=0602\n
|
||||
A: bmAttributes=e0\n
|
||||
A: busnum=3\n
|
||||
A: configuration=
|
||||
H: descriptors=12010002090001406B1D020015060302010109021900010100E0000904000001090000000705810304000C
|
||||
H: descriptors=12010002090001406B1D020002060302010109021900010100E0000904000001090000000705810304000C
|
||||
A: dev=189:256\n
|
||||
A: devnum=1\n
|
||||
A: devpath=0\n
|
||||
@@ -168,20 +164,20 @@ A: idProduct=0002\n
|
||||
A: idVendor=1d6b\n
|
||||
A: interface_authorized_default=1\n
|
||||
A: ltm_capable=no\n
|
||||
A: manufacturer=Linux 6.15.1 xhci-hcd\n
|
||||
A: manufacturer=Linux 6.2.0-34-generic xhci-hcd\n
|
||||
A: maxchild=12\n
|
||||
A: power/active_duration=2362684\n
|
||||
A: power/active_duration=337953872\n
|
||||
A: power/async=enabled\n
|
||||
A: power/autosuspend=0\n
|
||||
A: power/autosuspend_delay_ms=0\n
|
||||
A: power/connected_duration=96447784\n
|
||||
A: power/connected_duration=337978524\n
|
||||
A: power/control=auto\n
|
||||
A: power/level=auto\n
|
||||
A: power/runtime_active_kids=1\n
|
||||
A: power/runtime_active_time=2368910\n
|
||||
A: power/runtime_active_time=337962424\n
|
||||
A: power/runtime_enabled=enabled\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=94033284\n
|
||||
A: power/runtime_suspended_time=616\n
|
||||
A: power/runtime_usage=0\n
|
||||
A: power/wakeup=disabled\n
|
||||
A: power/wakeup_abort_count=\n
|
||||
@@ -199,15 +195,12 @@ A: rx_lanes=1\n
|
||||
A: serial=0000:00:14.0\n
|
||||
A: speed=480\n
|
||||
A: tx_lanes=1\n
|
||||
A: urbnum=7078\n
|
||||
A: urbnum=4969\n
|
||||
A: version= 2.00\n
|
||||
|
||||
P: /devices/pci0000:00/0000:00:14.0
|
||||
E: DRIVER=xhci_hcd
|
||||
E: ID_AUTOSUSPEND=1
|
||||
E: ID_MODEL_FROM_DATABASE=Alder Lake PCH USB 3.2 xHCI Host Controller
|
||||
E: ID_PATH=pci-0000:00:14.0
|
||||
E: ID_PATH_TAG=pci-0000_00_14_0
|
||||
E: ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
|
||||
E: ID_PCI_INTERFACE_FROM_DATABASE=XHCI
|
||||
E: ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
|
||||
@@ -221,15 +214,10 @@ E: SUBSYSTEM=pci
|
||||
A: ari_enabled=0\n
|
||||
A: broken_parity_status=0\n
|
||||
A: class=0x0c0330\n
|
||||
H: config=8680ED51060490020130030C000080000400161D6000000000000000000000000000000000000000000000004D1470C8000000007000000000000000FF010000FD0134A089C27F8000000000000000003F6DD80F000000000000000000000000316000000000000000000000000000000180C2C10800000000000000000000000590B7001804E0FE000000000000000009B014F01000400100000000C10A080000080E00001800008F50020000010000090000018680C00009001014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B50F010112000000
|
||||
H: config=8680ED51060490020130030C000080000400161D6000000000000000000000000000000000000000000000004D1470C8000000007000000000000000FF010000FD0134A089C27F8000000000000000003F6DD80F000000000000000000000000316000000000000000000000000000000180C2C1080000000000000000000000059087007805E0FE000000000000000009B014F01000400100000000C10A080000080E00001800008F50020000010000090000018680C00009001014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B50F010112000000
|
||||
A: consistent_dma_mask_bits=64\n
|
||||
A: d3cold_allowed=1\n
|
||||
A: dbc=disabled\n
|
||||
A: dbc_bInterfaceProtocol=01\n
|
||||
A: dbc_bcdDevice=0010\n
|
||||
A: dbc_idProduct=0010\n
|
||||
A: dbc_idVendor=1d6b\n
|
||||
A: dbc_poll_interval_ms=64\n
|
||||
A: device=0x51ed\n
|
||||
A: dma_mask_bits=64\n
|
||||
L: driver=../../../bus/pci/drivers/xhci_hcd
|
||||
@@ -239,39 +227,32 @@ L: firmware_node=../../LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:51
|
||||
A: index=7\n
|
||||
L: iommu=../../virtual/iommu/dmar1
|
||||
L: iommu_group=../../../kernel/iommu_groups/8
|
||||
A: irq=133\n
|
||||
A: irq=145\n
|
||||
A: label=Onboard - Other\n
|
||||
A: local_cpulist=0-15\n
|
||||
A: local_cpus=ffff\n
|
||||
A: modalias=pci:v00008086d000051EDsv0000144Dsd0000C870bc0Csc03i30\n
|
||||
A: msi_bus=1\n
|
||||
A: msi_irqs/133=msi\n
|
||||
A: msi_irqs/134=msi\n
|
||||
A: msi_irqs/135=msi\n
|
||||
A: msi_irqs/136=msi\n
|
||||
A: msi_irqs/137=msi\n
|
||||
A: msi_irqs/138=msi\n
|
||||
A: msi_irqs/139=msi\n
|
||||
A: msi_irqs/140=msi\n
|
||||
A: msi_irqs/145=msi\n
|
||||
A: numa_node=-1\n
|
||||
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 6 7 2112 7\nxHCI ring segments 27 27 4096 27\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\n
|
||||
A: pools=poolinfo - 0.1\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 0 128 0\nbuffer-32 0 0 32 0\nxHCI 1KB stream ctx arrays 0 0 1024 0\nxHCI 256 byte stream ctx arrays 0 0 256 0\nxHCI input/output contexts 6 9 2112 9\nxHCI ring segments 26 34 4096 34\nbuffer-2048 0 0 2048 0\nbuffer-512 0 0 512 0\nbuffer-128 0 32 128 1\nbuffer-32 0 0 32 0\n
|
||||
A: power/async=enabled\n
|
||||
A: power/control=auto\n
|
||||
A: power/runtime_active_kids=1\n
|
||||
A: power/runtime_active_time=2376480\n
|
||||
A: power/runtime_active_time=337964621\n
|
||||
A: power/runtime_enabled=enabled\n
|
||||
A: power/runtime_status=active\n
|
||||
A: power/runtime_suspended_time=94028360\n
|
||||
A: power/runtime_suspended_time=438\n
|
||||
A: power/runtime_usage=0\n
|
||||
A: power/wakeup=enabled\n
|
||||
A: power/wakeup_abort_count=0\n
|
||||
A: power/wakeup_active=0\n
|
||||
A: power/wakeup_active_count=1\n
|
||||
A: power/wakeup_active_count=7\n
|
||||
A: power/wakeup_count=0\n
|
||||
A: power/wakeup_expire_count=1\n
|
||||
A: power/wakeup_last_time_ms=41666464\n
|
||||
A: power/wakeup_max_time_ms=101\n
|
||||
A: power/wakeup_total_time_ms=101\n
|
||||
A: power/wakeup_expire_count=7\n
|
||||
A: power/wakeup_last_time_ms=336554844\n
|
||||
A: power/wakeup_max_time_ms=105\n
|
||||
A: power/wakeup_total_time_ms=721\n
|
||||
A: power_state=D0\n
|
||||
A: resource=0x000000601d160000 0x000000601d16ffff 0x0000000000140204\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n0x0000000000000000 0x0000000000000000 0x0000000000000000\n
|
||||
A: revision=0x01\n
|
||||
|
||||
@@ -19,7 +19,6 @@ envs.set('FP_DRIVERS_ALLOWLIST', ':'.join([
|
||||
'virtual_image',
|
||||
'virtual_device',
|
||||
'virtual_device_storage',
|
||||
'virtual_sdcp',
|
||||
]))
|
||||
|
||||
envs.set('FP_PRINTS_PATH', meson.project_source_root() / 'examples' / 'prints')
|
||||
@@ -53,9 +52,9 @@ drivers_tests = [
|
||||
'nb1010',
|
||||
'egis0570',
|
||||
'egismoc',
|
||||
# 'egismoc-05a1', # commented out until new capture with SDCP support can be provided
|
||||
# 'egismoc-0586', # commented out until new capture with SDCP support can be provided
|
||||
# 'egismoc-0587', # commented out until new capture with SDCP support can be provided
|
||||
'egismoc-05a1',
|
||||
'egismoc-0586',
|
||||
'egismoc-0587',
|
||||
'fpcmoc',
|
||||
'realtek',
|
||||
'realtek-5816',
|
||||
@@ -92,7 +91,6 @@ if get_option('introspection')
|
||||
virtual_devices_tests = [
|
||||
'virtual-image',
|
||||
'virtual-device',
|
||||
'virtual-sdcp',
|
||||
]
|
||||
|
||||
unittest_inspector = find_program('unittest_inspector.py')
|
||||
@@ -133,7 +131,6 @@ if get_option('introspection')
|
||||
suite: ut_suite,
|
||||
depends: libfprint_typelib,
|
||||
env: envs,
|
||||
workdir: meson.current_source_dir(),
|
||||
)
|
||||
endforeach
|
||||
|
||||
@@ -184,7 +181,6 @@ if get_option('introspection')
|
||||
meson.current_source_dir() / driver_test,
|
||||
],
|
||||
env: driver_envs,
|
||||
workdir: meson.current_source_dir(),
|
||||
suite: ['drivers'],
|
||||
timeout: 15,
|
||||
depends: libfprint_typelib,
|
||||
@@ -248,10 +244,13 @@ else
|
||||
endforeach
|
||||
endif
|
||||
|
||||
test_util_sources = [
|
||||
'test-utils.c',
|
||||
'test-device-fake.c',
|
||||
]
|
||||
test_utils = static_library('fprint-test-utils',
|
||||
sources: [
|
||||
'test-utils.c',
|
||||
'test-device-fake.c',
|
||||
],
|
||||
dependencies: libfprint_private_dep,
|
||||
install: false)
|
||||
|
||||
unit_tests = [
|
||||
'fpi-device',
|
||||
@@ -266,17 +265,6 @@ if 'virtual_image' in drivers
|
||||
]
|
||||
endif
|
||||
|
||||
if 'sdcp' in driver_helpers
|
||||
unit_tests += [
|
||||
'fpi-sdcp',
|
||||
]
|
||||
endif
|
||||
|
||||
test_utils = static_library('fprint-test-utils',
|
||||
sources: test_util_sources,
|
||||
dependencies: libfprint_private_dep,
|
||||
install: false)
|
||||
|
||||
unit_tests_deps = { 'fpi-assembling' : [cairo_dep] }
|
||||
|
||||
foreach test_name: unit_tests
|
||||
|
||||
@@ -262,6 +262,53 @@ test_device_identify_null_prints (void)
|
||||
g_assert_error (error, FP_DEVICE_ERROR, FP_DEVICE_ERROR_DATA_INVALID);
|
||||
}
|
||||
|
||||
static void
|
||||
test_device_persistent_data (void)
|
||||
{
|
||||
g_autoptr(FptContext) tctx = fpt_context_new_with_virtual_device (FPT_VIRTUAL_DEVICE_IMAGE);
|
||||
g_autoptr(GVariant) initial = NULL;
|
||||
g_autoptr(GVariant) loaded = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
guint8 *data = (guint8 *) 0xdeadbeef;
|
||||
gsize length = 1;
|
||||
|
||||
initial = g_variant_ref_sink (g_variant_new ("(s)", "stored data"));
|
||||
|
||||
g_assert_true (fp_device_get_persistent_data (tctx->device, &data, &length, &error));
|
||||
g_assert_cmpint (length, ==, 0);
|
||||
g_assert_null (data);
|
||||
g_assert_no_error (error);
|
||||
|
||||
/* Use the fact that this is a property that we can poke from the outside. */
|
||||
g_object_set (tctx->device, "fpi-persistent-data", initial, NULL);
|
||||
|
||||
/* Works now */
|
||||
g_assert_true (fp_device_get_persistent_data (tctx->device, &data, &length, &error));
|
||||
g_assert_cmpint (length, !=, 0);
|
||||
g_assert_nonnull (data);
|
||||
g_assert_no_error (error);
|
||||
|
||||
/* We can't load the data, as data has been set already. */
|
||||
g_assert_false (fp_device_set_persistent_data (tctx->device, data, length, &error));
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS);
|
||||
g_clear_pointer (&error, g_error_free);
|
||||
|
||||
/* Abuse that we can "load" again if the data is set to NULL.
|
||||
* This is an implementation detail and just a lack of error checking. */
|
||||
g_object_set (tctx->device, "fpi-persistent-data", NULL, NULL);
|
||||
|
||||
/* Incomplete data, causes parsing error */
|
||||
g_assert_false (fp_device_set_persistent_data (tctx->device, data, 5, &error));
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA);
|
||||
g_clear_pointer (&error, g_error_free);
|
||||
|
||||
g_assert_true (fp_device_set_persistent_data (tctx->device, data, length, &error));
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_object_get (tctx->device, "fpi-persistent-data", &loaded, NULL);
|
||||
g_assert_cmpvariant (initial, loaded);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
@@ -284,6 +331,7 @@ main (int argc, char *argv[])
|
||||
g_test_add_func ("/device/sync/has_storage", test_device_has_storage);
|
||||
g_test_add_func ("/device/sync/identify/cancelled", test_device_identify_cancelled);
|
||||
g_test_add_func ("/device/sync/identify/null-prints", test_device_identify_null_prints);
|
||||
g_test_add_func ("/device/persistent_data", test_device_persistent_data);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
|
||||
@@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Secure Device Connection Protocol (SDCP) support unit tests
|
||||
* Copyright (C) 2025 Joshua Grisham <josh@joshuagrisham.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#define FP_COMPONENT "test_fpi_sdcp"
|
||||
#include "fpi-log.h"
|
||||
|
||||
#include "fpi-sdcp.h"
|
||||
#include "fpi-sdcp-device.h"
|
||||
|
||||
/* We can re-use the test payloads from virtual-sdcp */
|
||||
#include "drivers/virtual-sdcp.h"
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static const guint8 from_hex_map[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567
|
||||
0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>?
|
||||
0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, // @abcdef
|
||||
};
|
||||
|
||||
static GBytes *
|
||||
g_bytes_from_hex (const gchar *hex)
|
||||
{
|
||||
g_autoptr(GBytes) res = NULL;
|
||||
guint8 b0, b1;
|
||||
gsize bytes_len = strlen (hex) / 2;
|
||||
guint8 *bytes = g_malloc0 (bytes_len);
|
||||
|
||||
for (int i = 0; i < strlen (hex) - 1; i += 2)
|
||||
{
|
||||
b0 = ((guint8) hex[i + 0] & 0x1F) ^ 0x10;
|
||||
b1 = ((guint8) hex[i + 1] & 0x1F) ^ 0x10;
|
||||
bytes[i / 2] = (guint8) (from_hex_map[b0] << 4) | from_hex_map[b1];
|
||||
}
|
||||
|
||||
res = g_bytes_new_take (bytes, bytes_len);
|
||||
|
||||
return g_steal_pointer (&res);
|
||||
}
|
||||
|
||||
static FpiSdcpClaim *
|
||||
get_fake_sdcp_claim (void)
|
||||
{
|
||||
FpiSdcpClaim *claim = g_new0 (FpiSdcpClaim, 1);
|
||||
|
||||
claim->model_certificate = g_bytes_from_hex (model_certificate_hex);
|
||||
claim->device_public_key = g_bytes_from_hex (device_public_key_hex);
|
||||
claim->firmware_public_key = g_bytes_from_hex (firmware_public_key_hex);
|
||||
claim->firmware_hash = g_bytes_from_hex (firmware_hash_hex);
|
||||
claim->model_signature = g_bytes_from_hex (model_signature_hex);
|
||||
claim->device_signature = g_bytes_from_hex (device_signature_hex);
|
||||
return g_steal_pointer (&claim);
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void
|
||||
test_generate_enrollment_id (void)
|
||||
{
|
||||
g_autoptr(GBytes) id = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) application_secret = g_bytes_from_hex (application_secret_hex);
|
||||
g_autoptr(GBytes) nonce = g_bytes_from_hex (enrollment_nonce_hex);
|
||||
g_autoptr(GBytes) expected_id = g_bytes_from_hex (enrollment_id_hex);
|
||||
|
||||
id = fpi_sdcp_generate_enrollment_id (application_secret, nonce, &error);
|
||||
|
||||
fp_dbg ("id:");
|
||||
fp_dbg_hex_dump_gbytes (id);
|
||||
|
||||
fp_dbg ("expected:");
|
||||
fp_dbg_hex_dump_gbytes (expected_id);
|
||||
|
||||
g_assert (g_bytes_equal (expected_id, id));
|
||||
g_assert_null (error);
|
||||
}
|
||||
|
||||
static void
|
||||
test_verify_identify (void)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) application_secret = g_bytes_from_hex (application_secret_hex);
|
||||
g_autoptr(GBytes) nonce = g_bytes_from_hex (identify_nonce_hex);
|
||||
g_autoptr(GBytes) id = g_bytes_from_hex (enrollment_id_hex);
|
||||
g_autoptr(GBytes) mac = g_bytes_from_hex (identify_mac_hex);
|
||||
|
||||
g_assert_true (fpi_sdcp_verify_identify (application_secret, nonce, id, mac, &error));
|
||||
g_assert_null (error);
|
||||
}
|
||||
|
||||
static void
|
||||
test_verify_reconnect (void)
|
||||
{
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GBytes) application_secret = g_bytes_from_hex (application_secret_hex);
|
||||
g_autoptr(GBytes) random = g_bytes_from_hex (reconnect_random_hex);
|
||||
g_autoptr(GBytes) mac = g_bytes_from_hex (reconnect_mac_hex);
|
||||
|
||||
g_assert_true (fpi_sdcp_verify_reconnect (application_secret, random, mac, &error));
|
||||
g_assert_null (error);
|
||||
}
|
||||
|
||||
static void
|
||||
test_verify_connect (void)
|
||||
{
|
||||
g_autoptr(GBytes) application_secret = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
g_autoptr(GBytes) host_private_key = g_bytes_from_hex (host_private_key_hex);
|
||||
g_autoptr(GBytes) host_random = g_bytes_from_hex (host_random_hex);
|
||||
g_autoptr(GBytes) device_random = g_bytes_from_hex (device_random_hex);
|
||||
g_autoptr(GBytes) connect_mac = g_bytes_from_hex (connect_mac_hex);
|
||||
FpiSdcpClaim *claim = get_fake_sdcp_claim ();
|
||||
|
||||
g_autoptr(GBytes) expected_application_secret = g_bytes_from_hex (application_secret_hex);
|
||||
|
||||
g_assert_true (fpi_sdcp_verify_connect (host_private_key,
|
||||
host_random,
|
||||
device_random,
|
||||
claim,
|
||||
connect_mac,
|
||||
TRUE,
|
||||
TRUE,
|
||||
&application_secret,
|
||||
&error));
|
||||
|
||||
g_assert_null (error);
|
||||
g_assert (g_bytes_get_size (application_secret) == SDCP_APPLICATION_SECRET_SIZE);
|
||||
|
||||
fp_dbg ("application_secret:");
|
||||
fp_dbg_hex_dump_gbytes (application_secret);
|
||||
|
||||
fp_dbg ("expected:");
|
||||
fp_dbg_hex_dump_gbytes (expected_application_secret);
|
||||
|
||||
g_assert_true (g_bytes_equal (expected_application_secret, application_secret));
|
||||
|
||||
fpi_sdcp_claim_free (claim);
|
||||
}
|
||||
|
||||
static void
|
||||
test_generate_random (void)
|
||||
{
|
||||
g_autoptr(GBytes) random = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
|
||||
random = fpi_sdcp_generate_random (&error);
|
||||
|
||||
g_assert_null (error);
|
||||
g_assert (g_bytes_get_size (random) == SDCP_RANDOM_SIZE);
|
||||
|
||||
fp_dbg ("random:");
|
||||
fp_dbg_hex_dump_gbytes (random);
|
||||
}
|
||||
|
||||
static void
|
||||
test_generate_host_key (void)
|
||||
{
|
||||
g_autoptr(GBytes) private_key = NULL;
|
||||
g_autoptr(GBytes) public_key = NULL;
|
||||
g_autoptr(GError) error = NULL;
|
||||
gsize len = 0;
|
||||
|
||||
fpi_sdcp_generate_host_key (&private_key, &public_key, &error);
|
||||
|
||||
g_assert_null (error);
|
||||
|
||||
g_bytes_get_data (private_key, &len);
|
||||
g_assert (len == 32);
|
||||
|
||||
fp_dbg ("private_key:");
|
||||
fp_dbg_hex_dump_gbytes (private_key);
|
||||
|
||||
g_bytes_get_data (public_key, &len);
|
||||
g_assert (len == SDCP_PUBLIC_KEY_SIZE);
|
||||
|
||||
fp_dbg ("public_key:");
|
||||
fp_dbg_hex_dump_gbytes (public_key);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
g_test_add_func ("/sdcp/generate_host_key", test_generate_host_key);
|
||||
g_test_add_func ("/sdcp/generate_random", test_generate_random);
|
||||
g_test_add_func ("/sdcp/verify_connect", test_verify_connect);
|
||||
g_test_add_func ("/sdcp/verify_reconnect", test_verify_reconnect);
|
||||
g_test_add_func ("/sdcp/verify_identify", test_verify_identify);
|
||||
g_test_add_func ("/sdcp/generate_enrollment_id", test_generate_enrollment_id);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys
|
||||
try:
|
||||
import gi
|
||||
import os
|
||||
|
||||
from gi.repository import GLib
|
||||
|
||||
import unittest
|
||||
except Exception as e:
|
||||
print("Missing dependencies: %s" % str(e))
|
||||
sys.exit(77)
|
||||
|
||||
FPrint = None
|
||||
|
||||
# Only permit loading virtual_sdcp driver for tests in this file
|
||||
os.environ['FP_DRIVERS_WHITELIST'] = 'virtual_sdcp'
|
||||
|
||||
if hasattr(os.environ, 'MESON_SOURCE_ROOT'):
|
||||
root = os.environ['MESON_SOURCE_ROOT']
|
||||
else:
|
||||
root = os.path.join(os.path.dirname(__file__), '..')
|
||||
|
||||
ctx = GLib.main_context_default()
|
||||
|
||||
class VirtualSDCPBase(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
os.environ['FP_VIRTUAL_SDCP'] = '1'
|
||||
|
||||
cls.ctx = FPrint.Context()
|
||||
|
||||
cls.dev = None
|
||||
for dev in cls.ctx.get_devices():
|
||||
cls.dev = dev
|
||||
break
|
||||
|
||||
assert cls.dev is not None, "You need to compile with virtual_sdcp for testing"
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
del cls.dev
|
||||
del cls.ctx
|
||||
|
||||
def setUp(self):
|
||||
self.ctx = FPrint.Context()
|
||||
self.assertIsNotNone(self.dev)
|
||||
self.assertFalse(self.dev.is_open())
|
||||
self.dev.open_sync()
|
||||
self.assertTrue(self.dev.is_open())
|
||||
|
||||
def tearDown(self):
|
||||
self.dev.close_sync()
|
||||
self.assertFalse(self.dev.is_open())
|
||||
del self.ctx
|
||||
|
||||
class VirtualSDCP(VirtualSDCPBase):
|
||||
|
||||
def test_connect(self):
|
||||
# Nothing to do here since setUp and tearDown will open and close the device
|
||||
pass
|
||||
|
||||
def test_reconnect(self):
|
||||
# Ensure device was opened once before, this may be a reconnect if
|
||||
# it is the same process as another test.
|
||||
self.dev.close_sync()
|
||||
|
||||
# Check that a reconnect happens on next open. To know about this, we
|
||||
# need to parse check log messages for that.
|
||||
success = [False]
|
||||
def log_func(domain, level, msg):
|
||||
print("log: '%s', '%s', '%s'" % (str(domain), str(level), msg))
|
||||
if msg == 'SDCP Reconnect succeeded':
|
||||
success[0] = True
|
||||
|
||||
# Call default handler
|
||||
GLib.log_default_handler(domain, level, msg)
|
||||
|
||||
handler_id = GLib.log_set_handler('libfprint-sdcp_device', GLib.LogLevelFlags.LEVEL_DEBUG, log_func)
|
||||
self.dev.open_sync()
|
||||
GLib.log_remove_handler('libfprint-sdcp_device', handler_id)
|
||||
assert success[0]
|
||||
|
||||
def test_list(self):
|
||||
prints = self.dev.list_prints_sync()
|
||||
assert len(prints) == 0
|
||||
|
||||
def test_enroll_list_verify(self):
|
||||
# Set up a new print
|
||||
template = FPrint.Print.new(self.dev)
|
||||
template.set_finger(FPrint.Finger.LEFT_THUMB)
|
||||
|
||||
# Enroll the new print
|
||||
new_print = self.dev.enroll_sync(template, None, None, None)
|
||||
self.assertIsInstance(new_print, FPrint.Print)
|
||||
|
||||
# Get the print list again and ensure there is exactly 1 print
|
||||
prints = self.dev.list_prints_sync()
|
||||
self.assertTrue(len(prints) == 1)
|
||||
|
||||
# Ensure the one print from list is the same as new_print
|
||||
self.assertTrue(prints[0].equal(new_print))
|
||||
|
||||
# Verify new_print
|
||||
verify_res, verify_print = self.dev.verify_sync(prints[0])
|
||||
self.assertTrue(verify_res)
|
||||
self.assertTrue(verify_print.equal(prints[0]))
|
||||
|
||||
# Set up a second new print
|
||||
template = FPrint.Print.new(self.dev)
|
||||
template.set_finger(FPrint.Finger.LEFT_INDEX)
|
||||
|
||||
# Enroll the second print
|
||||
new_print2 = self.dev.enroll_sync(template, None, None, None)
|
||||
self.assertIsInstance(new_print2, FPrint.Print)
|
||||
|
||||
# Get the print list again and ensure there is exactly 2 prints
|
||||
prints = self.dev.list_prints_sync()
|
||||
self.assertTrue(len(prints) == 2)
|
||||
|
||||
# Ensure the second print from list is the same as new_print2
|
||||
self.assertTrue(prints[1].equal(new_print2))
|
||||
|
||||
class VirtualSDCPNoReconnect(VirtualSDCPBase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
os.environ['FP_VIRTUAL_SDCP_NO_RECONNECT'] = '1'
|
||||
super().setUpClass()
|
||||
|
||||
def test_connect(self):
|
||||
# Nothing to do here since setUp and tearDown will open and close the device
|
||||
pass
|
||||
|
||||
def test_reconnect(self):
|
||||
# Ensure device was opened once before, this may be a reconnect if
|
||||
# it is the same process as another test.
|
||||
self.dev.close_sync()
|
||||
|
||||
# Check that a reconnect happens on next open. To know about this, we
|
||||
# need to parse check log messages for that.
|
||||
success = [False]
|
||||
def log_func(domain, level, msg):
|
||||
print("log: '%s', '%s', '%s'" % (str(domain), str(level), msg))
|
||||
if msg == 'SDCP Reconnect succeeded':
|
||||
success[0] = True
|
||||
|
||||
# Call default handler
|
||||
GLib.log_default_handler(domain, level, msg)
|
||||
|
||||
handler_id = GLib.log_set_handler('libfprint-sdcp_device', GLib.LogLevelFlags.LEVEL_DEBUG, log_func)
|
||||
self.dev.open_sync()
|
||||
GLib.log_remove_handler('libfprint-sdcp_device', handler_id)
|
||||
|
||||
# Ensure that we did NOT see "SDCP Reconnect succeeded" in the log
|
||||
assert success[0] == False
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
gi.require_version('FPrint', '2.0')
|
||||
from gi.repository import FPrint
|
||||
except Exception as e:
|
||||
print("Missing dependencies: %s" % str(e))
|
||||
sys.exit(77)
|
||||
|
||||
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))
|
||||
Reference in New Issue
Block a user