diff --git a/libfprint/drivers/goodixtls/goodix.c b/libfprint/drivers/goodixtls/goodix.c index c3596fc8..cdd9a9d4 100644 --- a/libfprint/drivers/goodixtls/goodix.c +++ b/libfprint/drivers/goodixtls/goodix.c @@ -17,6 +17,8 @@ // 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-ssm.h" +#include "fpi-usb-transfer.h" #define FP_COMPONENT "goodixtls" #include @@ -33,22 +35,23 @@ #include "goodixtls.h" typedef struct { - pthread_t tls_server_thread; - gint tls_server_sock; - SSL_CTX *tls_server_ctx; + GoodixTlsServer* tls_hop; - GSource *timeout; + GSource* timeout; - guint8 cmd; + guint8 cmd; - gboolean ack; - gboolean reply; + gboolean ack; + gboolean reply; + gboolean tls; - GoodixCmdCallback callback; - gpointer user_data; + GoodixCmdCallback callback; + gpointer user_data; - guint8 *data; - guint32 length; + guint8* data; + guint32 length; + + GoodixCallbackInfo* tls_ready_callback; } FpiDeviceGoodixTlsPrivate; G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE(FpiDeviceGoodixTls, fpi_device_goodixtls, @@ -269,8 +272,9 @@ void goodix_receive_ack(FpDevice *dev, guint8 *data, guint16 length, } if (!priv->reply) { - goodix_receive_done(dev, NULL, 0, NULL); - return; + G_DEBUG_HERE(); + goodix_receive_done(dev, NULL, 0, NULL); + return; } priv->ack = FALSE; @@ -286,14 +290,17 @@ void goodix_receive_protocol(FpDevice *dev, guint8 *data, guint32 length) { gboolean valid_checksum, valid_null_checksum; // TODO implement checksum. if (!goodix_decode_protocol(data, length, &cmd, &payload, &payload_len, - &valid_checksum, &valid_null_checksum)) - // Protocol is not full, we still need data. - // TODO implement protocol assembling. - return; + &valid_checksum, &valid_null_checksum)) { + fp_err("Incomplete, size: %d", length); + // Protocol is not full, we still need data. + // TODO implement protocol assembling. + return; + } if (cmd == GOODIX_CMD_ACK) { - goodix_receive_ack(dev, payload, payload_len, NULL, NULL); - return; + fp_dbg("got ack"); + goodix_receive_ack(dev, payload, payload_len, NULL, NULL); + return; } if (priv->cmd != cmd) { @@ -311,6 +318,35 @@ void goodix_receive_protocol(FpDevice *dev, guint8 *data, guint32 length) { goodix_receive_done(dev, payload, payload_len, NULL); } +static void goodix_receive_tls(FpDevice* dev, guint8* data, guint32 length) +{ + FpiDeviceGoodixTls* self = FPI_DEVICE_GOODIXTLS(dev); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + g_autofree guint8* payload = NULL; + guint16 payload_len; + gboolean valid_checksum; // TODO implement checksum. + guint8 flags; + + if (!goodix_decode_pack(data, length, &flags, &payload, &payload_len, + &valid_checksum)) { + fp_err("Incomplete, size tls: %d", length); + // Protocol is not full, we still need data. + // TODO implement protocol assembling. + return; + } + + if (!priv->reply) { + fp_warn("Didn't excpect a reply for command: 0x%02x", priv->cmd); + return; + } + + if (priv->ack) + fp_warn("Didn't got ACK for command: 0x%02x", priv->cmd); + + goodix_receive_done(dev, payload, payload_len, NULL); +} + void goodix_receive_pack(FpDevice *dev, guint8 *data, guint32 length) { FpiDeviceGoodixTls *self = FPI_DEVICE_GOODIXTLS(dev); FpiDeviceGoodixTlsPrivate *priv = @@ -325,19 +361,28 @@ void goodix_receive_pack(FpDevice *dev, guint8 *data, guint32 length) { priv->length += length; if (!goodix_decode_pack(priv->data, priv->length, &flags, &payload, - &payload_len, &valid_checksum)) - // Packet is not full, we still need data. - return; + &payload_len, &valid_checksum)) { + // Packet is not full, we still need data. + fp_dbg("not full packet"); + return; + } switch (flags) { case GOODIX_FLAGS_MSG_PROTOCOL: - goodix_receive_protocol(dev, payload, payload_len); - break; + fp_dbg("Got protocol msg"); + goodix_receive_protocol(dev, payload, payload_len); + break; case GOODIX_FLAGS_TLS: - // TLS message sending it to TLS server. - // TODO - break; + fp_dbg("Got TLS msg"); + if (!priv->tls) { + fp_warn("unexpected tls packet"); + } + goodix_receive_done(dev, payload, payload_len, NULL); + + // TLS message sending it to TLS server. + // TODO + break; default: fp_warn("Unknown flags: 0x%02x", flags); @@ -397,24 +442,26 @@ void goodix_receive_data(FpDevice *dev) { gboolean goodix_send_data(FpDevice *dev, guint8 *data, guint32 length, GDestroyNotify free_func, GError **error) { FpiDeviceGoodixTls *self = FPI_DEVICE_GOODIXTLS(dev); - FpiDeviceGoodixTlsClass *class = FPI_DEVICE_GOODIXTLS_GET_CLASS(self); - FpiUsbTransfer *transfer = fpi_usb_transfer_new(dev); - - transfer->short_is_error = TRUE; + FpiDeviceGoodixTlsClass* class = FPI_DEVICE_GOODIXTLS_GET_CLASS(self); for (guint32 i = 0; i < length; i += GOODIX_EP_OUT_MAX_BUF_SIZE) { - fpi_usb_transfer_fill_bulk_full(transfer, class->ep_out, data + i, - GOODIX_EP_OUT_MAX_BUF_SIZE, NULL); - - if (!fpi_usb_transfer_submit_sync(transfer, GOODIX_TIMEOUT, error)) { - if (free_func) free_func(data); + FpiUsbTransfer* transfer = fpi_usb_transfer_new(dev); + transfer->short_is_error = TRUE; + + fpi_usb_transfer_fill_bulk_full(transfer, class->ep_out, data + i, + GOODIX_EP_OUT_MAX_BUF_SIZE, NULL); + + if (!fpi_usb_transfer_submit_sync(transfer, GOODIX_TIMEOUT, error)) { + if (free_func) + free_func(data); + fpi_usb_transfer_unref(transfer); + return FALSE; + } fpi_usb_transfer_unref(transfer); - return FALSE; - } } - if (free_func) free_func(data); - fpi_usb_transfer_unref(transfer); + if (free_func) + free_func(data); return TRUE; } @@ -494,26 +541,27 @@ void goodix_send_nop(FpDevice *dev, GoodixNoneCallback callback, goodix_receive_done(dev, NULL, 0, NULL); } -void goodix_send_mcu_get_image(FpDevice *dev, GoodixNoneCallback callback, - gpointer user_data) { - GoodixDefault payload = {.unused_flags = 0x01}; - GoodixCallbackInfo *cb_info; +void goodix_send_mcu_get_image(FpDevice* dev, GoodixImageCallback callback, + gpointer user_data) +{ + GoodixDefault payload = {.unused_flags = 0x01}; + GoodixCallbackInfo* cb_info; - if (callback) { - cb_info = malloc(sizeof(GoodixCallbackInfo)); + if (callback) { + cb_info = malloc(sizeof(GoodixCallbackInfo)); - cb_info->callback = G_CALLBACK(callback); - cb_info->user_data = user_data; + cb_info->callback = G_CALLBACK(callback); + cb_info->user_data = user_data; - goodix_send_protocol(dev, GOODIX_CMD_MCU_GET_IMAGE, (guint8 *)&payload, - sizeof(payload), NULL, TRUE, GOODIX_TIMEOUT, FALSE, - goodix_receive_none, cb_info); - return; - } + goodix_send_protocol(dev, GOODIX_CMD_MCU_GET_IMAGE, (guint8*) &payload, + sizeof(payload), NULL, TRUE, GOODIX_TIMEOUT, TRUE, + goodix_receive_default, cb_info); + return; + } - goodix_send_protocol(dev, GOODIX_CMD_MCU_GET_IMAGE, (guint8 *)&payload, - sizeof(payload), NULL, TRUE, GOODIX_TIMEOUT, FALSE, NULL, - NULL); + goodix_send_protocol(dev, GOODIX_CMD_MCU_GET_IMAGE, (guint8*) &payload, + sizeof(payload), NULL, TRUE, GOODIX_TIMEOUT, TRUE, + NULL, NULL); } void goodix_send_mcu_switch_to_fdt_down(FpDevice *dev, guint8 *mode, @@ -825,27 +873,29 @@ void goodix_send_query_mcu_state(FpDevice *dev, GoodixDefaultCallback callback, NULL); } -void goodix_send_request_tls_connection(FpDevice *dev, - GoodixNoneCallback callback, - gpointer user_data) { - GoodixNone payload = {}; - GoodixCallbackInfo *cb_info; - - if (callback) { - cb_info = malloc(sizeof(GoodixCallbackInfo)); - - cb_info->callback = G_CALLBACK(callback); - cb_info->user_data = user_data; +void goodix_send_request_tls_connection(FpDevice* dev, + GoodixDefaultCallback callback, + gpointer user_data) +{ + GoodixNone payload = {}; + GoodixCallbackInfo* cb_info; + + if (callback) { + cb_info = malloc(sizeof(GoodixCallbackInfo)); + + cb_info->callback = G_CALLBACK(callback); + cb_info->user_data = user_data; + + goodix_send_protocol(dev, GOODIX_CMD_REQUEST_TLS_CONNECTION, + (guint8*) &payload, sizeof(payload), NULL, TRUE, + GOODIX_TIMEOUT, TRUE, goodix_receive_default, + cb_info); + return; + } goodix_send_protocol(dev, GOODIX_CMD_REQUEST_TLS_CONNECTION, - (guint8 *)&payload, sizeof(payload), NULL, TRUE, - GOODIX_TIMEOUT, FALSE, goodix_receive_none, cb_info); - return; - } - - goodix_send_protocol(dev, GOODIX_CMD_REQUEST_TLS_CONNECTION, - (guint8 *)&payload, sizeof(payload), NULL, TRUE, - GOODIX_TIMEOUT, FALSE, NULL, NULL); + (guint8*) &payload, sizeof(payload), NULL, TRUE, + GOODIX_TIMEOUT, TRUE, NULL, NULL); } void goodix_send_tls_successfully_established(FpDevice *dev, @@ -970,31 +1020,246 @@ gboolean goodix_dev_deinit(FpDevice *dev, GError **error) { // ---- TLS SECTION START ---- +void goodix_read_tls(FpDevice* dev, GoodixTlsCallback callback, + gpointer user_data) +{ + + fp_dbg("goodix_read_tls()"); + FpiDeviceGoodixTls* self = FPI_DEVICE_GOODIXTLS(dev); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + priv->callback = callback; + priv->user_data = user_data; + priv->reply = TRUE; + priv->cmd = 0; + goodix_receive_data(FP_DEVICE(self)); +} + enum tls_states { TLS_SERVER_INIT, TLS_SERVER_HANDSHAKE_INIT, TLS_NUM_STATES, }; -void goodix_tls_run_state(FpiSsm *ssm, FpDevice *dev) { - switch (fpi_ssm_get_cur_state(ssm)) { - case TLS_SERVER_INIT: - tls_server_init(ssm); - break; +static void on_goodix_tls_server_ready(GoodixTlsServer* server, GError* err, + gpointer dev) +{ + if (err) { + fp_err("server ready failed: %s", err->message); + return; + } + fp_dbg("TLS connection ready"); +} - case TLS_SERVER_HANDSHAKE_INIT: - tls_server_handshake_init(); - break; - } +static void on_goodix_tls_read_handshake(FpDevice* dev, guint8* data, + guint16 length, gpointer user_data, + GError* error) +{ + // goodix_tls_handshake_state* state = (goodix_tls_handshake_state*) + // user_data; + FpiSsm* ssm = user_data; + if (error) { + fpi_ssm_mark_failed(ssm, error); + return; + } + FpiDeviceGoodixTls* self = + FPI_DEVICE_GOODIXTLS(fpi_ssm_get_data(user_data)); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + + int sent = goodix_tls_client_send(priv->tls_hop, data, length); + if (sent < 0) { + fpi_ssm_mark_failed(ssm, g_error_new(g_io_error_quark(), sent, + "failed to sent data to " + "tls server")); + return; + } + fpi_ssm_next_state(ssm); +} + +enum goodix_tls_handshake_stages { + TLS_HANDSHAKE_STAGE_HELLO_S, + TLS_HANDSHAKE_STAGE_KH_EXCHANGE, + TLS_HANDSHAKE_STAGE_CHANGE_CIPHER_C, + TLS_HANDSHAKE_STAGE_HANDSHAKE_C, + TLS_HANDSHAKE_STAGE_CHANGE_CIPHER_S, + + TLS_HANDSHAKE_STAGE_NUM, +}; + +static void on_tls_successfully_established(FpDevice* dev, gpointer user_data, + GError* error) +{ + + fp_dbg("HANDSHAKE DONE"); + FpiDeviceGoodixTls* self = FPI_DEVICE_GOODIXTLS(dev); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + ((GoodixNoneCallback) priv->tls_ready_callback->callback)( + dev, priv->tls_ready_callback->user_data, NULL); +} +static void tls_handshake_done(FpiSsm* ssm, FpDevice* dev, GError* error) +{ + if (error) { + fp_dbg("failed to do tls handshake: %s (code: %d)", error->message, + error->code); + } + goodix_send_tls_successfully_established( + dev, on_tls_successfully_established, NULL); +} +static void tls_handshake_run(FpiSsm* ssm, FpDevice* dev) +{ + FpiDeviceGoodixTls* self = FPI_DEVICE_GOODIXTLS(dev); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + + int stage = fpi_ssm_get_cur_state(ssm); + if (stage == TLS_HANDSHAKE_STAGE_HELLO_S) { + guint8 buff[1024]; + int size = goodix_tls_client_recv(priv->tls_hop, buff, sizeof(buff)); + if (size < 0) { + fpi_ssm_mark_failed(ssm, g_error_new(g_io_error_quark(), size, + "failed to read tls server " + "hello")); + return; + } + GError* err = NULL; + if (!goodix_send_pack(dev, GOODIX_FLAGS_TLS, buff, size, NULL, &err)) { + fpi_ssm_mark_failed(ssm, err); + return; + } + fpi_ssm_next_state(ssm); + } + else if (stage < TLS_HANDSHAKE_STAGE_CHANGE_CIPHER_S) { + // Still proxying from hardware + fpi_ssm_set_data(ssm, dev, NULL); + goodix_read_tls(dev, on_goodix_tls_read_handshake, ssm); + } + else if (stage == TLS_HANDSHAKE_STAGE_CHANGE_CIPHER_S) { + fp_dbg("Reading to proxy back"); + guint8 buff[1024]; + int size = goodix_tls_client_recv(priv->tls_hop, buff, sizeof(buff)); + if (size < 0) { + fpi_ssm_mark_failed(ssm, g_error_new(g_io_error_quark(), size, + "failed to read server " + "handshake")); + + return; + } + GError* err = NULL; + if (!goodix_send_data(dev, buff, size, NULL, &err)) { + fpi_ssm_mark_failed(ssm, err); + return; + } + fpi_ssm_next_state(ssm); + } +} + +static void do_tls_handshake(FpDevice* dev) +{ + fpi_ssm_start(fpi_ssm_new(dev, tls_handshake_run, TLS_HANDSHAKE_STAGE_NUM), + tls_handshake_done); +} + +static void on_goodix_request_tls_connection(FpDevice* dev, guint8* data, + guint16 length, gpointer user_data, + GError* error) +{ + if (error) { + fp_err("failed to get tls handshake: %s", error->message); + goodix_send_tls_successfully_established(FP_DEVICE(dev), NULL, NULL); + return; + } + FpiDeviceGoodixTls* self = FPI_DEVICE_GOODIXTLS(user_data); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + + goodix_tls_client_send(priv->tls_hop, data, length); + + do_tls_handshake(dev); +} + +static void goodix_tls_ready(GoodixTlsServer* server, GError* err, gpointer dev) +{ + if (err) { + fp_err("failed to init tls server: %s, code: %d", err->message, + err->code); + return; + } + goodix_send_request_tls_connection(FP_DEVICE(dev), + on_goodix_request_tls_connection, dev); } void goodix_tls_complete(FpiSsm *ssm, FpDevice *dev, GError *error) { fpi_image_device_activate_complete(FP_IMAGE_DEVICE(dev), error); } -void goodix_tls(FpDevice *dev) { - fpi_ssm_start(fpi_ssm_new(dev, goodix_tls_run_state, TLS_NUM_STATES), - goodix_tls_complete); +void goodix_tls(FpDevice* dev, GoodixNoneCallback callback, gpointer user_data) +{ + fp_dbg("Starting up goodix tls server"); + FpiDeviceGoodixTls* self = FPI_DEVICE_GOODIXTLS(dev); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + g_assert(priv->tls_hop == NULL); + priv->tls_hop = malloc(sizeof(GoodixTlsServer)); + + if (!priv->tls_ready_callback) { + priv->tls_ready_callback = malloc(sizeof(GoodixCallbackInfo)); + } + priv->tls_ready_callback->callback = G_CALLBACK(callback); + priv->tls_ready_callback->user_data = user_data; + GoodixTlsServer* s = priv->tls_hop; + s->connection_callback = on_goodix_tls_server_ready; + s->user_data = self; + GError* err = NULL; + if (!goodix_tls_server_init(priv->tls_hop, &err)) { + fp_err("failed to init tls server, error: %s, code: %d", err->message, + err->code); + return; + } + + goodix_tls_ready(s, err, self); +} +static void goodix_tls_ready_image_handler(FpDevice* dev, guint8* data, + guint16 length, gpointer user_data, + GError* error) +{ + + g_autofree GoodixCallbackInfo* cb_info = user_data; + GoodixImageCallback callback = (GoodixImageCallback) cb_info->callback; + if (error) { + callback(dev, NULL, 0, error, cb_info->user_data); + return; + } + FpiDeviceGoodixTls* self = FPI_DEVICE_GOODIXTLS(dev); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + goodix_tls_client_send(priv->tls_hop, data, length); + + const guint16 size = -1; + guint8* buff = malloc(size); + GError* err = NULL; + if (!goodix_tls_server_receive(priv->tls_hop, buff, size, &err)) { + callback(dev, NULL, 0, err, cb_info->user_data); + return; + } + + callback(dev, buff, size, cb_info->user_data, NULL); +} + +void goodix_tls_read_image(FpDevice* dev, GoodixImageCallback callback, + gpointer user_data) +{ + g_assert(callback); + FpiDeviceGoodixTls* self = FPI_DEVICE_GOODIXTLS(dev); + FpiDeviceGoodixTlsPrivate* priv = + fpi_device_goodixtls_get_instance_private(self); + GoodixCallbackInfo* cb_info = malloc(sizeof(GoodixImageCallback)); + + cb_info->callback = G_CALLBACK(callback); + cb_info->user_data = user_data; + + goodix_send_mcu_get_image(dev, goodix_tls_ready_image_handler, cb_info); } // ---- TLS SECTION END ---- diff --git a/libfprint/drivers/goodixtls/goodix.h b/libfprint/drivers/goodixtls/goodix.h index 131e2025..7e8a9799 100644 --- a/libfprint/drivers/goodixtls/goodix.h +++ b/libfprint/drivers/goodixtls/goodix.h @@ -65,6 +65,10 @@ typedef void (*GoodixNoneCallback)(FpDevice *dev, gpointer user_data, typedef void (*GoodixDefaultCallback)(FpDevice *dev, guint8 *data, guint16 length, gpointer user_data, GError *error); +typedef GoodixDefaultCallback GoodixTlsCallback; + +typedef void (*GoodixImageCallback)(FpDevice* dev, guint8* data, guint16 length, + gpointer user_data, GError* error); gchar *data_to_str(guint8 *data, guint32 length); @@ -132,7 +136,7 @@ void goodix_send_protocol(FpDevice *dev, guint8 cmd, guint8 *payload, void goodix_send_nop(FpDevice *dev, GoodixNoneCallback callback, gpointer user_data); -void goodix_send_mcu_get_image(FpDevice *dev, GoodixNoneCallback callback, +void goodix_send_mcu_get_image(FpDevice *dev, GoodixImageCallback callback, gpointer user_data); void goodix_send_mcu_switch_to_fdt_down(FpDevice *dev, guint8 *mode, @@ -192,8 +196,8 @@ void goodix_send_firmware_version(FpDevice *dev, void goodix_send_query_mcu_state(FpDevice *dev, GoodixDefaultCallback callback, gpointer user_data); -void goodix_send_request_tls_connection(FpDevice *dev, - GoodixNoneCallback callback, +void goodix_send_request_tls_connection(FpDevice* dev, + GoodixDefaultCallback callback, gpointer user_data); void goodix_send_tls_successfully_established(FpDevice *dev, @@ -225,10 +229,16 @@ gboolean goodix_dev_deinit(FpDevice *dev, GError **error); // ---- TLS SECTION START ---- -void goodix_tls_run_state(FpiSsm *ssm, FpDevice *dev); +void goodix_read_tls(FpDevice* dev, GoodixTlsCallback callback, + gpointer user_data); + +void goodix_tls_run_state(FpiSsm* ssm, FpDevice* dev); void goodix_tls_complete(FpiSsm *ssm, FpDevice *dev, GError *error); -void goodix_tls(FpDevice *dev); +void goodix_tls(FpDevice* dev, GoodixNoneCallback callback, gpointer user_data); + +void goodix_tls_read_image(FpDevice* dev, GoodixImageCallback callback, + gpointer user_data); // ---- TLS SECTION END ---- diff --git a/libfprint/drivers/goodixtls/goodix511.c b/libfprint/drivers/goodixtls/goodix511.c index 68af76f1..c6a838b4 100644 --- a/libfprint/drivers/goodixtls/goodix511.c +++ b/libfprint/drivers/goodixtls/goodix511.c @@ -17,6 +17,14 @@ // 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 "fp-device.h" +#include "fp-image-device.h" +#include "fpi-assembling.h" +#include "fpi-image-device.h" +#include "fpi-ssm.h" +#include "glibconfig.h" +#include "gusb/gusb-device.h" +#include #define FP_COMPONENT "goodixtls511" #include @@ -40,17 +48,16 @@ G_DEFINE_TYPE(FpiDeviceGoodixTls511, fpi_device_goodixtls511, // ---- ACTIVE SECTION START ---- enum activate_states { - ACTIVATE_READ_AND_NOP, - ACTIVATE_ENABLE_CHIP, - ACTIVATE_NOP, - ACTIVATE_CHECK_FW_VER, - ACTIVATE_CHECK_PSK, - ACTIVATE_RESET, - BREAK, - ACTIVATE_SET_MCU_IDLE, - ACTIVATE_SET_MCU_CONFIG, - ACTIVATE_SET_POWERDOWN_SCAN_FREQUENCY, - ACTIVATE_NUM_STATES, + ACTIVATE_READ_AND_NOP, + ACTIVATE_ENABLE_CHIP, + ACTIVATE_NOP, + ACTIVATE_CHECK_FW_VER, + ACTIVATE_CHECK_PSK, + ACTIVATE_RESET, + ACTIVATE_SET_MCU_IDLE, + ACTIVATE_SET_MCU_CONFIG, + ACTIVATE_SET_POWERDOWN_SCAN_FREQUENCY, + ACTIVATE_NUM_STATES, }; static void check_none(FpDevice *dev, gpointer user_data, GError *error) { @@ -150,17 +157,61 @@ static void check_preset_psk_read(FpDevice *dev, gboolean success, fpi_ssm_next_state(user_data); } - +static void check_idle(FpDevice* dev, gpointer user_data, GError* err) +{ + G_DEBUG_HERE(); + + if (err) { + fpi_ssm_mark_failed(user_data, err); + return; + } + fpi_ssm_next_state(user_data); +} +static void check_config_upload(FpDevice* dev, gboolean success, + gpointer user_data, GError* error) +{ + G_DEBUG_HERE(); + if (error) { + fpi_ssm_mark_failed(user_data, error); + } + else if (!success) { + GError* err = malloc(sizeof(GError)); + err->message = "Failed to upload config"; + fpi_ssm_mark_failed(user_data, err); + } + else { + fpi_ssm_next_state(user_data); + } +} +static void check_powerdown_scan_freq(FpDevice* dev, gboolean success, + gpointer user_data, GError* error) +{ + if (error) { + fpi_ssm_mark_failed(user_data, error); + } + else if (!success) { + GError* err = malloc(sizeof(GError)); + err->message = "Failed set powerdown"; + fpi_ssm_mark_failed(user_data, err); + } + else { + fpi_ssm_next_state(user_data); + } +} static void activate_run_state(FpiSsm *ssm, FpDevice *dev) { GError *error = NULL; switch (fpi_ssm_get_cur_state(ssm)) { case ACTIVATE_READ_AND_NOP: - // Nop seems to clear the previous command buffer. But we are unable to - // do so. - goodix_receive_data(dev); - goodix_send_nop(dev, check_none, ssm); - break; + /* Uncomment below in case the successfully established bit didn't get + run and you get a timeout when trying to rerun */ + // goodix_send_tls_successfully_established(dev, NULL, NULL); + // exit(0); + // Nop seems to clear the previous command buffer. But we are + // unable to do so. + goodix_receive_data(dev); + goodix_send_nop(dev, check_none, ssm); + break; case ACTIVATE_ENABLE_CHIP: goodix_send_enable_chip(dev, TRUE, check_none, ssm); @@ -183,38 +234,135 @@ static void activate_run_state(FpiSsm *ssm, FpDevice *dev) { goodix_send_reset(dev, TRUE, 20, check_reset, ssm); break; - case BREAK: - g_set_error_literal(&error, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Break"); - fpi_ssm_mark_failed(ssm, error); - break; + case ACTIVATE_SET_MCU_IDLE: + goodix_send_mcu_switch_to_idle_mode(dev, 20, check_idle, ssm); + break; + + case ACTIVATE_SET_MCU_CONFIG: + goodix_send_upload_config_mcu(dev, goodix_511_config, + sizeof(goodix_511_config), NULL, + check_config_upload, ssm); + break; + + case ACTIVATE_SET_POWERDOWN_SCAN_FREQUENCY: + goodix_send_set_powerdown_scan_frequency( + dev, 100, check_powerdown_scan_freq, ssm); + break; + } +} - // case ACTIVATE_SET_MCU_IDLE: - // goodix_send_mcu_switch_to_idle_mode(ssm, 20); - // break; +static void tls_activation_complete(FpDevice* dev, gpointer user_data, + GError* error) +{ + if (error) { + fp_err("failed to complete tls activation: %s", error->message); + return; + } + FpImageDevice* image_dev = FP_IMAGE_DEVICE(dev); - // case ACTIVATE_SET_MCU_CONFIG: - // goodix_send_upload_config_mcu( - // ssm, goodix_511_config, sizeof(goodix_511_config), NULL, NULL, - // NULL); - // break; + fpi_image_device_activate_complete(image_dev, error); +} - // case ACTIVATE_SET_POWERDOWN_SCAN_FREQUENCY: - // goodix_send_set_powerdown_scan_frequency(ssm, 100, NULL, NULL); - // break; - } +static void activate_complete(FpiSsm* ssm, FpDevice* dev, GError* error) +{ + G_DEBUG_HERE(); + if (!error) + goodix_tls(dev, tls_activation_complete, NULL); +} + +// ---- ACTIVE SECTION END ---- + +// ----------------------------------------------------------------------------- + +// ---- SCAN SECTION START ---- + +enum SCAN_STAGES { + SCAN_STAGE_SWITCH_TO_FDT_MODE, + SCAN_STAGE_SWITCH_TO_FDT_DOWN, + SCAN_STAGE_GET_IMG, + + SCAN_STAGE_NUM, +}; + +static void check_none_cmd(FpDevice* dev, guint8* data, guint16 len, + gpointer ssm, GError* err) +{ + if (err) { + fpi_ssm_mark_failed(ssm, err); + return; + } + fpi_ssm_next_state(ssm); } -static void activate_complete(FpiSsm *ssm, FpDevice *dev, GError *error) { - FpImageDevice *image_dev = FP_IMAGE_DEVICE(dev); +static void scan_on_read_img(FpDevice* dev, guint8* data, guint16 len, + gpointer ssm, GError* err) +{ + if (err) { + fpi_ssm_mark_failed(ssm, err); + return; + } + fp_dbg("Got image"); + FILE* out = fopen("./fingerprint.pgm", "wb"); + fwrite(data, sizeof(guint8), len, out); + fclose(out); + fpi_ssm_next_state(ssm); +} - fpi_image_device_activate_complete(image_dev, error); +static void scan_get_img(FpDevice* dev, FpiSsm* ssm) +{ + goodix_tls_read_image(dev, scan_on_read_img, ssm); +} +const guint8 fdt_switch_state_mode[] = {0x0d, 0x01, 0x80, 0xaf, 0x80, 0xa4, + 0x80, 0xb8, 0x80, 0xa8, 0x80, 0xb7}; + +const guint8 fdt_switch_state_down[] = {0x0c, 0x01, 0x80, 0xaf, 0x80, 0xa4, + 0x80, 0xb8, 0x80, 0xa8, 0x80, 0xb7}; + +/* + +const guint8 fdt_switch_state_mode[] = {0x0d, 0x01, 0x80, 0xaf, 0x80, 0xa3, + 0x80, 0xb7, 0x80, 0xa7, 0x80, 0xb6}; + +const guint8 fdt_switch_state_down[] = {0x0d, 0x01, 0x80, 0xaf, 0x80, + 0xbf, 0x80, 0xa4, 0x80, 0xb8, + 0x80, 0xa8, 0x80, 0xb7}; + */ + +static void scan_run_state(FpiSsm* ssm, FpDevice* dev) +{ + switch (fpi_ssm_get_cur_state(ssm)) { + case SCAN_STAGE_SWITCH_TO_FDT_MODE: + goodix_send_mcu_switch_to_fdt_mode(dev, fdt_switch_state_mode, + sizeof(fdt_switch_state_mode), NULL, + check_none_cmd, ssm); + break; + case SCAN_STAGE_SWITCH_TO_FDT_DOWN: + goodix_send_mcu_switch_to_fdt_down(dev, fdt_switch_state_down, + sizeof(fdt_switch_state_down), NULL, + check_none_cmd, ssm); + break; + case SCAN_STAGE_GET_IMG: + scan_get_img(dev, ssm); + break; + } +} - if (!error) goodix_tls(dev); +static void scan_complete(FpiSsm* ssm, FpDevice* dev, GError* error) +{ + if (error) { + fp_err("failed to scan: %s (code: %d)", error->message, error->code); + return; + } + fp_dbg("finished scan"); } -// ---- ACTIVE SECTION END ---- +static void scan_start(FpiDeviceGoodixTls511* dev) +{ + fpi_ssm_start(fpi_ssm_new(FP_DEVICE(dev), scan_run_state, SCAN_STAGE_NUM), + scan_complete); +} -// ----------------------------------------------------------------------------- +// ---- SCAN SECTION END ---- // ---- DEV SECTION START ---- @@ -249,8 +397,17 @@ static void dev_activate(FpImageDevice *img_dev) { activate_complete); } -static void dev_change_state(FpImageDevice *img_dev, - FpiImageDeviceState state) {} + + +static void dev_change_state(FpImageDevice* img_dev, FpiImageDeviceState state) +{ + FpiDeviceGoodixTls511* self = FPI_DEVICE_GOODIXTLS511(img_dev); + G_DEBUG_HERE(); + + if (state == FPI_IMAGE_DEVICE_STATE_AWAIT_FINGER_ON) { + scan_start(self); + } +} static void dev_deactivate(FpImageDevice *img_dev) { fpi_image_device_deactivate_complete(img_dev, NULL); diff --git a/libfprint/drivers/goodixtls/goodix_proto.c b/libfprint/drivers/goodixtls/goodix_proto.c index 980f3599..1b2aafa8 100644 --- a/libfprint/drivers/goodixtls/goodix_proto.c +++ b/libfprint/drivers/goodixtls/goodix_proto.c @@ -19,6 +19,7 @@ #include #include +#include #include "goodix_proto.h" diff --git a/libfprint/drivers/goodixtls/goodix_proto.h b/libfprint/drivers/goodixtls/goodix_proto.h index d42ca870..ac27ce63 100644 --- a/libfprint/drivers/goodixtls/goodix_proto.h +++ b/libfprint/drivers/goodixtls/goodix_proto.h @@ -19,7 +19,7 @@ #pragma once -#define GOODIX_EP_IN_MAX_BUF_SIZE (0x2000) +#define GOODIX_EP_IN_MAX_BUF_SIZE (0x10000) #define GOODIX_EP_OUT_MAX_BUF_SIZE (0x40) #define GOODIX_NULL_CHECKSUM (0x88) diff --git a/libfprint/drivers/goodixtls/goodixtls.c b/libfprint/drivers/goodixtls/goodixtls.c index 62118ac1..10e76712 100644 --- a/libfprint/drivers/goodixtls/goodixtls.c +++ b/libfprint/drivers/goodixtls/goodixtls.c @@ -24,18 +24,30 @@ #include #include #include +#include +#include #include #include #include #include #include "drivers_api.h" +#include "fp-device.h" +#include "fpi-device.h" +#include "glibconfig.h" +#include "goodix.h" #include "goodixtls.h" -int sock; -FpiSsm *fpi_ssm; -pthread_t server; -SSL_CTX *ctx; +static GError* err_from_ssl() +{ + GError* err = malloc(sizeof(GError)); + unsigned long code = ERR_get_error(); + err->code = code; + const char* msg = ERR_reason_error_string(code); + err->message = malloc(strlen(msg)); + strcpy(err->message, msg); + return err; +} static unsigned int tls_server_psk_server_callback(SSL *ssl, const char *identity, @@ -45,168 +57,131 @@ static unsigned int tls_server_psk_server_callback(SSL *ssl, fp_dbg("Provided PSK R is too long for OpenSSL"); return 0; } - - psk = (unsigned char *)&goodix_511_psk_0; - - return sizeof(goodix_511_psk_0); + fp_dbg("PSK WANTED %d", max_psk_len); + // I don't know why we must use OPENSSL_hexstr2buf but just copying zeros + // doesn't work + const char* buff = "000000000000000000000000000000000000000000000000000000000" + "0000000"; + long len = 0; + unsigned char* key = OPENSSL_hexstr2buf(buff, &len); + memcpy(psk, key, len); + OPENSSL_free(key); + + return len; } -int tls_server_create_socket(int port) { - int s; - struct sockaddr_in addr; - - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = htonl(INADDR_ANY); - - s = socket(AF_INET, SOCK_STREAM, 0); - if (s < 0) { - fp_dbg("Unable to create TLS server socket"); - fpi_ssm_mark_failed(fpi_ssm, fpi_device_error_new_msg( - FP_DEVICE_ERROR_GENERAL, - "Unable to create TLS server socket")); - return -1; - } +static SSL_CTX* tls_server_create_ctx(void) +{ + const SSL_METHOD* method; - if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { - fp_dbg("Unable to bind to TLS server socket"); - fpi_ssm_mark_failed(fpi_ssm, fpi_device_error_new_msg( - FP_DEVICE_ERROR_GENERAL, - "Unable to bind to TLS server socket")); - return -1; - } + method = TLS_server_method(); - if (listen(s, 1) < 0) { - fp_dbg("Unable to listen to TLS server socket"); - fpi_ssm_mark_failed(fpi_ssm, fpi_device_error_new_msg( - FP_DEVICE_ERROR_GENERAL, - "Unable to listen to TLS server socket")); - return -1; - } + SSL_CTX* ctx = SSL_CTX_new(method); + if (!ctx) { + return NULL; + } - return s; + return ctx; } -SSL_CTX *tls_server_create_ctx(void) { - const SSL_METHOD *method; - - method = SSLv23_server_method(); - - ctx = SSL_CTX_new(method); - if (!ctx) { - return NULL; - } - - return ctx; +static void tls_server_config_ctx(SSL_CTX* ctx) +{ + SSL_CTX_set_ecdh_auto(ctx, 1); + SSL_CTX_set_dh_auto(ctx, 1); + SSL_CTX_set_cipher_list(ctx, "ALL"); + SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); + SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION); + SSL_CTX_set_psk_server_callback(ctx, tls_server_psk_server_callback); } -void tls_server_config_ctx(void) { - SSL_CTX_set_ecdh_auto(ctx, 1); - SSL_CTX_set_dh_auto(ctx, 1); - SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); - SSL_CTX_set_max_proto_version(ctx, TLS1_2_VERSION); - SSL_CTX_set_cipher_list(ctx, "ALL"); - - SSL_CTX_set_psk_server_callback(ctx, tls_server_psk_server_callback); +int goodix_tls_client_send(GoodixTlsServer* self, guint8* data, guint16 length) +{ + fp_dbg("sent: %s size: %d", data_to_str(data, length), length); + return write(self->client_fd, data, length * sizeof(guint8)); +} +int goodix_tls_client_recv(GoodixTlsServer* self, guint8* data, guint16 length) { + return read(self->client_fd, data, length * sizeof(guint8)); } -void *tls_server_loop(void *arg) { - // Handle connections - while (1) { - struct sockaddr_in addr; - guint len = sizeof(addr); - SSL *ssl; - const char reply[] = "Hello Goodix\n"; - - int client = accept(sock, (struct sockaddr *)&addr, &len); - if (client < 0) { - printf("%s\n", strerror(errno)); - fp_dbg("TLS server unable to accept request"); - kill(getpid(), SIGKILL); - // exit(EXIT_FAILURE); - } - - ssl = SSL_new(ctx); - SSL_set_fd(ssl, client); - - if (SSL_accept(ssl) <= 0) { - ERR_print_errors_fp(stderr); - } else { - SSL_write(ssl, reply, strlen(reply)); +int goodix_tls_server_receive(GoodixTlsServer* self, guint8* data, + guint32 length, GError** error) +{ + fp_dbg("READ START"); + int retr = SSL_read(self->ssl_layer, data, length * sizeof(guint8)); + if (retr <= 0) { + g_set_error(error, g_io_channel_error_quark(), retr, + ""); // err_from_ssl(retr); } - SSL_shutdown(ssl); - SSL_free(ssl); - close(client); - - kill(getpid(), SIGKILL); - } + fp_dbg("READ END"); + return retr; } -void tls_server_stop(void) { - close(sock); - SSL_CTX_free(ctx); +static void tls_config_ssl(SSL* ssl) +{ + SSL_set_min_proto_version(ssl, TLS1_2_VERSION); + SSL_set_max_proto_version(ssl, TLS1_2_VERSION); + SSL_set_psk_server_callback(ssl, tls_server_psk_server_callback); + SSL_set_cipher_list(ssl, "ALL"); } -void *tls_server_handshake_loop(void *arg) { - struct sockaddr_in addr; - guint len = sizeof(addr); - SSL *ssl; - - int client = accept(sock, (struct sockaddr *)&addr, &len); - if (client < 0) { - printf("%s\n", strerror(errno)); - fp_dbg("TLS server unable to accept socket request"); - } else { - ssl = SSL_new(ctx); - SSL_set_fd(ssl, client); - - if (SSL_accept(ssl) <= 0) { - printf("%s\n", strerror(errno)); - fp_dbg("TLS server unable to accept handshake request"); +static void* goodix_tls_init_serve(void* me) +{ + GoodixTlsServer* self = me; + self->ssl_layer = SSL_new(self->ssl_ctx); + tls_config_ssl(self->ssl_layer); + SSL_set_fd(self->ssl_layer, self->sock_fd); + fp_dbg("TLS server waiting to accept..."); + int retr = SSL_accept(self->ssl_layer); + fp_dbg("TLS server accept done"); + if (retr <= 0) { + self->connection_callback(self, err_from_ssl(), self->user_data); } - } - return 0; -} - -void tls_server_handshake_init(void) { - int err = pthread_create(&server, NULL, &tls_server_handshake_loop, NULL); - if (err != 0) { - fp_dbg("Unable to create TLS server thread"); - fpi_ssm_mark_failed(fpi_ssm, fpi_device_error_new_msg( - FP_DEVICE_ERROR_GENERAL, - "Unable to create TLS server thread")); - } else { - fp_dbg("TLS server thread created"); - fpi_ssm_next_state(fpi_ssm); - } + else { + self->connection_callback(self, NULL, self->user_data); + } + return NULL; } -void tls_server_init(FpiSsm *ssm) { - fpi_ssm = ssm; - - SSL_load_error_strings(); - OpenSSL_add_ssl_algorithms(); +gboolean goodix_tls_server_deinit(GoodixTlsServer* self, GError** error) +{ + SSL_shutdown(self->ssl_layer); + SSL_free(self->ssl_layer); - ctx = tls_server_create_ctx(); + close(self->client_fd); + close(self->sock_fd); - if (ctx == NULL) { - fp_dbg("Unable to create TLS server context"); - fpi_ssm_mark_failed( - ssm, fpi_device_error_new_msg(FP_DEVICE_ERROR_GENERAL, - "Unable to create TLS server context")); - return; - } + SSL_CTX_free(self->ssl_ctx); - tls_server_config_ctx(); + return TRUE; +} - sock = tls_server_create_socket(GOODIX_TLS_SERVER_PORT); - if (sock == -1) { - fp_dbg("Unable to create TLS server socket"); - fpi_ssm_mark_failed( - ssm, fpi_device_error_new_msg(FP_DEVICE_ERROR_GENERAL, - "Unable to create TLS server context")); - return; - } +gboolean goodix_tls_server_init(GoodixTlsServer* self, GError** error) +{ + g_assert(self->connection_callback); + SSL_load_error_strings(); + OpenSSL_add_ssl_algorithms(); + SSL_library_init(); + self->ssl_ctx = tls_server_create_ctx(); + tls_server_config_ctx(self->ssl_ctx); + + int socks[2] = {0, 0}; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) != 0) { + g_set_error(error, G_FILE_ERROR, errno, + "failed to create socket pair: %s", strerror(errno)); + return FALSE; + } + self->sock_fd = socks[0]; + self->client_fd = socks[1]; + + if (self->ssl_ctx == NULL) { + fp_dbg("Unable to create TLS server context\n"); + *error = fpi_device_error_new_msg(FP_DEVICE_ERROR_GENERAL, "Unable to " + "create TLS " + "server " + "context"); + return FALSE; + } + pthread_create(&self->serve_thread, 0, goodix_tls_init_serve, self); - fpi_ssm_next_state(ssm); + return TRUE; } diff --git a/libfprint/drivers/goodixtls/goodixtls.h b/libfprint/drivers/goodixtls/goodixtls.h index 25052381..a7d5b949 100644 --- a/libfprint/drivers/goodixtls/goodixtls.h +++ b/libfprint/drivers/goodixtls/goodixtls.h @@ -19,25 +19,72 @@ #pragma once +#include + +#include + #define GOODIX_TLS_SERVER_PORT 4433 +// static const guint8 goodix_511_psk_0[64] = {0}; static const guint8 goodix_511_psk_0[] = { 0xba, 0x1a, 0x86, 0x03, 0x7c, 0x1d, 0x3c, 0x71, 0xc3, 0xaf, 0x34, 0x49, 0x55, 0xbd, 0x69, 0xa9, 0xa9, 0x86, 0x1d, 0x9e, 0x91, 0x1f, 0xa2, 0x49, 0x85, 0xb6, 0x77, 0xe8, 0xdb, 0xd7, 0x2d, 0x43}; -SSL_CTX *tls_server_create_ctx(void); +struct _GoodixTlsServer; + +typedef void (*GoodixTlsServerSendCallback)(struct _GoodixTlsServer* self, + guint8* data, guint16 length); + +typedef void (*GoodixTlsServerConnectionCallback)(struct _GoodixTlsServer* self, + GError* error, + gpointer user_data); + +typedef void (*GoodixTlsServerDecodedCallback)(struct _GoodixTlsServer* self, + guint8* data, gsize length, + GError* error); + +typedef struct _GoodixTlsServer { + // This callback should be called when a TLS packet must be send to the + // device + // GoodixTlsServerSendCallback send_callback; + + // This callback should be called when the connection is established. The + // error should be NULL. It can also be called when the connection fail. In + // this case, the error should not be NULL. + GoodixTlsServerConnectionCallback connection_callback; + + // This callback should be called when a TLS packet is decoded. The error + // should be NULL. + // It can also be called when the server fail to decode a packet. In this + // case, the error should not be NULL. + // GoodixTlsServerDecodedCallback decoded_callback; -int tls_server_create_socket(int port); + // Put what you need here. + gpointer user_data; // Passed to all callbacks + SSL_CTX* ssl_ctx; + int sock_fd; + SSL* ssl_layer; + // SSL* cli_ssl_layer; + int client_fd; + pthread_t serve_thread; +} GoodixTlsServer; -void tls_server_config_ctx(void); +// This is called only once to init the TLS server. +// Return TRUE on success, FALSE otherwise and error should be set. +gboolean goodix_tls_server_init(GoodixTlsServer* self, GError** error); -__attribute__((__noreturn__)) void *tls_server_loop(void *arg); +gboolean goodix_tls_init_cli(GoodixTlsServer* self, GError** err); -void tls_server_stop(void); +// This can be called multiple times. It is called when the device send a TLS +// packet. +int goodix_tls_server_receive(GoodixTlsServer* self, guint8* data, + guint32 length, GError** error); -void *tls_server_handshake_loop(void *arg); +int goodix_tls_client_send(GoodixTlsServer* self, guint8* data, guint16 length); -void tls_server_handshake_init(void); +int goodix_tls_client_recv(GoodixTlsServer* self, guint8* data, guint16 length); -void tls_server_init(FpiSsm *ssm); +// This is called only once to deinit the TLS server. +// Return TRUE on success, FALSE otherwise and error should be set. +gboolean goodix_tls_server_deinit(GoodixTlsServer* self, GError** error);