Compare commits

...

12 Commits

Author SHA1 Message Date
Benjamin Berg
f2dfa2ae0a sdcp-device: Use a key DB for testing 2022-02-14 17:20:00 +01:00
Benjamin Berg
67723675d2 sdcp-device: Use predictable keys and random numbers for testing
If FP_DEVICE_EMULATION is set, then switch to using predictable EC
ephemeral key and random numbers. This should allow recording and
replaying real device interactions using umockdev.
2022-02-14 17:20:00 +01:00
Benjamin Berg
39e060a71b port to low level EC key functions
This will allow creating a fixed key for testing
2022-02-14 17:20:00 +01:00
Benjamin Berg
2a99fb0aca saner public key param 2022-02-14 17:20:00 +01:00
Benjamin Berg
197d60cdb1 fixups: use static OID data 2022-02-14 17:20:00 +01:00
Benjamin Berg
2677ccc0c2 ci: Enable SDCP helper for tests 2022-02-14 17:20:00 +01:00
Benjamin Berg
f921aaf0a8 tests: Add SDCP virtual device test 2022-02-14 17:20:00 +01:00
Benjamin Berg
8ecd78e982 virtual-sdcp: Add a virtual SDCP device
This device is designed to talk to an external executable. This
executable can be provided/created using the test implementation from
Microsoft.
2022-02-14 17:20:00 +01:00
Benjamin Berg
991e6e2343 sdcp: Add SDCP base class
This adds a base class for SDCP devices. Not all functionality has been
fully tested, in particular the code to verify the model certificate is
most likely broken or incomplete. One problem there is that there is no
code to find the root CA to trust.

See: #257
2022-02-14 17:20:00 +01:00
Benjamin Berg
24b02b943f device: Add new FP_DEVICE_ERROR_UNTRUSTED error code
Throw a specific error when we are unable to verify the integrety of the
device.
2022-02-14 17:19:59 +01:00
Benjamin Berg
8240bf54e6 print: Add an SDCP print type
For now it is identical to a RAW print. However, this is likely to
change in the future.
2022-02-14 17:19:05 +01:00
Benjamin Berg
6539cde70d ci: Include SDCP test binary in image 2022-02-14 17:19:05 +01:00
20 changed files with 2773 additions and 5 deletions

View File

@@ -63,7 +63,7 @@ test:
variables: variables:
- $CI_PIPELINE_SOURCE == "schedule" - $CI_PIPELINE_SOURCE == "schedule"
script: script:
- meson --werror -Ddrivers=all -Db_coverage=true . _build - meson --werror -Ddrivers=all -Db_coverage=true -Dsdcp_virt_binary=/usr/local/bin/sdcp_virt_device . _build
- ninja -C _build - ninja -C _build
- meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3 - meson test -C _build --print-errorlogs --no-stdsplit --timeout-multiplier 3
- ninja -C _build coverage - ninja -C _build coverage
@@ -83,7 +83,7 @@ test_valgrind:
variables: variables:
- $CI_PIPELINE_SOURCE == "schedule" - $CI_PIPELINE_SOURCE == "schedule"
script: script:
- meson -Ddrivers=all . _build - meson -Ddrivers=all -Dsdcp_virt_binary=/usr/local/bin/sdcp_virt_device . _build
- ninja -C _build - ninja -C _build
- meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind - meson test -C _build --print-errorlogs --no-stdsplit --setup=valgrind
artifacts: artifacts:
@@ -167,8 +167,20 @@ container_fedora_build:
vala vala
libpcap-devel libpcap-devel
libudev-devel libudev-devel
mbedtls-devel
FDO_DISTRIBUTION_EXEC: | FDO_DISTRIBUTION_EXEC: |
git clone https://github.com/martinpitt/umockdev.git && \ git clone https://github.com/martinpitt/umockdev.git && \
cd umockdev && \ cd umockdev && \
meson _build --prefix=/usr && \ meson _build --prefix=/usr && \
ninja -C _build && ninja -C _build install ninja -C _build && ninja -C _build install
cd /tmp
mkdir -p /usr/local/bin
git clone https://github.com/benzea/SecureDeviceConnectionProtocol.git
# Don't bother with cmake
gcc -l mbedcrypto -I SecureDeviceConnectionProtocol/src/include \
SecureDeviceConnectionProtocol/src/test/virt_device.c \
SecureDeviceConnectionProtocol/src/client/client.c \
SecureDeviceConnectionProtocol/src/test/helpers.c \
SecureDeviceConnectionProtocol/src/test/testkeys.c \
-o /usr/local/bin/sdcp_virt_device
rm -rf SecureDeviceConnectionProtocol

View File

@@ -100,6 +100,12 @@ FP_TYPE_IMAGE_DEVICE
FpImageDevice FpImageDevice
</SECTION> </SECTION>
<SECTION>
<FILE>fp-sdcp-device</FILE>
FP_TYPE_SDCP_DEVICE
FpSdcpDevice
</SECTION>
<SECTION> <SECTION>
<FILE>fp-print</FILE> <FILE>fp-print</FILE>
FP_TYPE_PRINT FP_TYPE_PRINT
@@ -215,6 +221,26 @@ fpi_image_device_retry_scan
fpi_image_device_set_bz3_threshold fpi_image_device_set_bz3_threshold
</SECTION> </SECTION>
<SECTION>
<FILE>fpi-sdcp-device</FILE>
<TITLE>Internal FpSdcpDevice</TITLE>
FpiSdcpClaim
FpSdcpDeviceClass
fpi_sdcp_claim_copy
fpi_sdcp_claim_free
fpi_sdcp_claim_get_type
fpi_sdcp_claim_new
fpi_sdcp_device_connect_complete
fpi_sdcp_device_get_connect_data
fpi_sdcp_device_get_reconnect_data
fpi_sdcp_device_reconnect_complete
fpi_sdcp_device_enroll_commit_complete
fpi_sdcp_device_enroll_ready
fpi_sdcp_device_enroll_set_nonce
fpi_sdcp_device_identify_retry
fpi_sdcp_device_identify_complete
</SECTION>
<SECTION> <SECTION>
<FILE>fpi-log</FILE> <FILE>fpi-log</FILE>
fp_dbg fp_dbg

View File

@@ -28,6 +28,7 @@
<xi:include href="xml/fp-context.xml"/> <xi:include href="xml/fp-context.xml"/>
<xi:include href="xml/fp-device.xml"/> <xi:include href="xml/fp-device.xml"/>
<xi:include href="xml/fp-image-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-print.xml"/>
<xi:include href="xml/fp-image.xml"/> <xi:include href="xml/fp-image.xml"/>
</part> </part>
@@ -38,6 +39,7 @@
<title>Device methods for drivers</title> <title>Device methods for drivers</title>
<xi:include href="xml/fpi-device.xml"/> <xi:include href="xml/fpi-device.xml"/>
<xi:include href="xml/fpi-image-device.xml"/> <xi:include href="xml/fpi-image-device.xml"/>
<xi:include href="xml/fpi-sdcp-device.xml"/>
</chapter> </chapter>
<chapter id="driver-helpers"> <chapter id="driver-helpers">

View File

@@ -0,0 +1,676 @@
/*
* Virtual driver for SDCP device debugging
*
* 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
*/
/*
* This is a virtual test driver to test the basic SDCP functionality.
* It uses the test binaries from Microsoft, which were extended to allow
* a simple chat with the device.
* The environment variable contains the to be executed binary including
* arguments. This binary should be compiled from the code in
* https://github.com/Microsoft/SecureDeviceConnectionProtocol
* or, until it is merged upstream
* https://github.com/benzea/SecureDeviceConnectionProtocol
*
* Note that using this as an external executable has the advantage that we
* do not need to link against mbedtls or any other crypto library.
*/
#define FP_COMPONENT "virtual_sdcp"
#include "fpi-log.h"
#include "fpi-ssm.h"
#include "../fpi-sdcp-device.h"
#include <glib/gstdio.h>
#include <gio/gio.h>
struct _FpDeviceVirtualSdcp
{
FpSdcpDevice parent;
GSubprocess *proc;
GOutputStream *proc_stdin;
GInputStream *proc_stdout;
/* Only valid while a read/write is pending */
GByteArray *msg_out;
GByteArray *msg_in;
GByteArray *connect_msg;
};
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)
guint8 ca_1[] = {
0x30, 0x82, 0x03, 0xFD, 0x30, 0x82, 0x03, 0x82, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x33,
0x00, 0x00, 0x00, 0x07, 0xE8, 0x9D, 0x61, 0x62, 0x4D, 0x46, 0x0F, 0x95, 0x00, 0x00, 0x00, 0x00,
0x00, 0x07, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x30, 0x81,
0x84, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0A, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67,
0x74, 0x6F, 0x6E, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65,
0x64, 0x6D, 0x6F, 0x6E, 0x64, 0x31, 0x1E, 0x30, 0x1C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x15,
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72,
0x61, 0x74, 0x69, 0x6F, 0x6E, 0x31, 0x2E, 0x30, 0x2C, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25,
0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x53, 0x65,
0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x50, 0x43, 0x41,
0x20, 0x32, 0x30, 0x31, 0x38, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x38, 0x30, 0x31, 0x33, 0x31, 0x31,
0x39, 0x35, 0x34, 0x35, 0x33, 0x5A, 0x17, 0x0D, 0x32, 0x38, 0x30, 0x31, 0x33, 0x31, 0x32, 0x30,
0x30, 0x34, 0x35, 0x33, 0x5A, 0x30, 0x7D, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,
0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0A, 0x57,
0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x74, 0x6F, 0x6E, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55,
0x04, 0x07, 0x13, 0x07, 0x52, 0x65, 0x64, 0x6D, 0x6F, 0x6E, 0x64, 0x31, 0x1E, 0x30, 0x1C, 0x06,
0x03, 0x55, 0x04, 0x0A, 0x13, 0x15, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20,
0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x31, 0x27, 0x30, 0x25, 0x06,
0x03, 0x55, 0x04, 0x03, 0x13, 0x1E, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x48, 0x65,
0x6C, 0x6C, 0x6F, 0x20, 0x31, 0x39, 0x42, 0x39, 0x32, 0x39, 0x36, 0x35, 0x20, 0x43, 0x41, 0x20,
0x32, 0x30, 0x31, 0x38, 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02,
0x01, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x03, 0x42, 0x00, 0x04, 0xBE,
0x4B, 0x90, 0x6E, 0x24, 0xFC, 0xA1, 0x53, 0xC8, 0xA7, 0x3C, 0x70, 0xE8, 0x97, 0xCD, 0x1B, 0x31,
0xE4, 0x95, 0x91, 0x7A, 0x58, 0xA2, 0x86, 0xA8, 0x70, 0xF6, 0x09, 0x30, 0x77, 0x99, 0x3D, 0x10,
0xDF, 0xF7, 0x95, 0x0F, 0x68, 0x83, 0xE6, 0xA4, 0x11, 0x7C, 0xDA, 0x82, 0xE7, 0x0B, 0x8B, 0xF2,
0x9D, 0x6B, 0x5B, 0xF5, 0x3E, 0x77, 0xB4, 0xC1, 0x0E, 0x49, 0x00, 0x83, 0xBA, 0x94, 0xF8, 0xA3,
0x82, 0x01, 0xD7, 0x30, 0x82, 0x01, 0xD3, 0x30, 0x10, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01,
0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x1D, 0x06, 0x03, 0x55, 0x1D, 0x0E,
0x04, 0x16, 0x04, 0x14, 0x13, 0x93, 0xC8, 0xCD, 0xF2, 0x23, 0x9A, 0x2D, 0xC6, 0x9B, 0x2A, 0xEB,
0x9A, 0xAB, 0x99, 0x0B, 0x56, 0x04, 0x5E, 0x7C, 0x30, 0x65, 0x06, 0x03, 0x55, 0x1D, 0x20, 0x04,
0x5E, 0x30, 0x5C, 0x30, 0x06, 0x06, 0x04, 0x55, 0x1D, 0x20, 0x00, 0x30, 0x52, 0x06, 0x0C, 0x2B,
0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x4C, 0x83, 0x7D, 0x01, 0x01, 0x30, 0x42, 0x30, 0x40, 0x06,
0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x34, 0x68, 0x74, 0x74, 0x70, 0x3A,
0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x2E,
0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73, 0x2F, 0x44, 0x6F, 0x63, 0x73, 0x2F,
0x52, 0x65, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x6F, 0x72, 0x79, 0x2E, 0x68, 0x74, 0x6D, 0x00, 0x30,
0x19, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x04, 0x0C, 0x1E, 0x0A,
0x00, 0x53, 0x00, 0x75, 0x00, 0x62, 0x00, 0x43, 0x00, 0x41, 0x30, 0x0B, 0x06, 0x03, 0x55, 0x1D,
0x0F, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0F, 0x06, 0x03, 0x55, 0x1D, 0x13, 0x01, 0x01,
0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x1F, 0x06, 0x03, 0x55, 0x1D, 0x23, 0x04,
0x18, 0x30, 0x16, 0x80, 0x14, 0xDA, 0xCA, 0x4B, 0xD0, 0x4C, 0x56, 0x03, 0x27, 0x5F, 0x97, 0xEB,
0x75, 0xA3, 0x02, 0xC3, 0xBF, 0x45, 0x9C, 0xF8, 0xB1, 0x30, 0x68, 0x06, 0x03, 0x55, 0x1D, 0x1F,
0x04, 0x61, 0x30, 0x5F, 0x30, 0x5D, 0xA0, 0x5B, 0xA0, 0x59, 0x86, 0x57, 0x68, 0x74, 0x74, 0x70,
0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74,
0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73, 0x2F, 0x63, 0x72, 0x6C, 0x2F,
0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x25, 0x32, 0x30, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x25,
0x32, 0x30, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x25, 0x32, 0x30, 0x44, 0x65, 0x76, 0x69, 0x63,
0x65, 0x73, 0x25, 0x32, 0x30, 0x50, 0x43, 0x41, 0x25, 0x32, 0x30, 0x32, 0x30, 0x31, 0x38, 0x2E,
0x63, 0x72, 0x6C, 0x30, 0x75, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04,
0x69, 0x30, 0x67, 0x30, 0x65, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86,
0x59, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72,
0x6F, 0x73, 0x6F, 0x66, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73,
0x2F, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2F, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x25, 0x32,
0x30, 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x25, 0x32, 0x30, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x25,
0x32, 0x30, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x25, 0x32, 0x30, 0x50, 0x43, 0x41, 0x25,
0x32, 0x30, 0x32, 0x30, 0x31, 0x38, 0x2E, 0x63, 0x72, 0x74, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86,
0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x03, 0x69, 0x00, 0x30, 0x66, 0x02, 0x31, 0x00, 0x87, 0xB6,
0x82, 0xF3, 0xDA, 0xBE, 0xB1, 0x7B, 0x98, 0x7D, 0x3D, 0x0A, 0x90, 0xA8, 0xF5, 0xBF, 0x15, 0xC3,
0xEE, 0x8A, 0x4E, 0xC0, 0x7B, 0x10, 0x1D, 0xA9, 0xE3, 0x0B, 0xEC, 0x2C, 0x53, 0x4E, 0xA7, 0xBD,
0xF1, 0x6C, 0xAD, 0x18, 0x55, 0xBA, 0x25, 0x73, 0x55, 0xB7, 0x5B, 0x12, 0x24, 0xF4, 0x02, 0x31,
0x00, 0xAF, 0x02, 0x9C, 0x4B, 0x92, 0xD0, 0x72, 0xA5, 0x80, 0xCA, 0x69, 0x2B, 0x38, 0x50, 0x64,
0xD8, 0x58, 0x9E, 0xEA, 0xD6, 0x35, 0xCF, 0x68, 0x98, 0x92, 0x81, 0x09, 0x61, 0xC2, 0xBD, 0xB1,
0x4C, 0x7F, 0xAE, 0x55, 0x7B, 0xFC, 0x22, 0xDD, 0xD6, 0xB7, 0x7C, 0xB5, 0xA8, 0x18, 0x5D, 0x33,
0x04
};
guint8 ca_2[] = {
0x30, 0x82, 0x04, 0x56, 0x30, 0x82, 0x03, 0xDC, 0xA0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x13, 0x33,
0x00, 0x00, 0x00, 0x03, 0x6C, 0xCF, 0xED, 0xE2, 0x44, 0x70, 0x19, 0xBF, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x30, 0x81,
0x94, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13,
0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0A, 0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67,
0x74, 0x6F, 0x6E, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65,
0x64, 0x6D, 0x6F, 0x6E, 0x64, 0x31, 0x1E, 0x30, 0x1C, 0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x15,
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72,
0x61, 0x74, 0x69, 0x6F, 0x6E, 0x31, 0x3E, 0x30, 0x3C, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x35,
0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x20, 0x45, 0x43, 0x43, 0x20, 0x44, 0x65,
0x76, 0x69, 0x63, 0x65, 0x73, 0x20, 0x52, 0x6F, 0x6F, 0x74, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69,
0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x20, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79,
0x20, 0x32, 0x30, 0x31, 0x37, 0x30, 0x1E, 0x17, 0x0D, 0x31, 0x38, 0x30, 0x31, 0x32, 0x35, 0x31,
0x39, 0x34, 0x39, 0x33, 0x38, 0x5A, 0x17, 0x0D, 0x33, 0x33, 0x30, 0x31, 0x32, 0x35, 0x31, 0x39,
0x35, 0x39, 0x33, 0x38, 0x5A, 0x30, 0x81, 0x84, 0x31, 0x0B, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04,
0x06, 0x13, 0x02, 0x55, 0x53, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0A,
0x57, 0x61, 0x73, 0x68, 0x69, 0x6E, 0x67, 0x74, 0x6F, 0x6E, 0x31, 0x10, 0x30, 0x0E, 0x06, 0x03,
0x55, 0x04, 0x07, 0x13, 0x07, 0x52, 0x65, 0x64, 0x6D, 0x6F, 0x6E, 0x64, 0x31, 0x1E, 0x30, 0x1C,
0x06, 0x03, 0x55, 0x04, 0x0A, 0x13, 0x15, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74,
0x20, 0x43, 0x6F, 0x72, 0x70, 0x6F, 0x72, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x31, 0x2E, 0x30, 0x2C,
0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x25, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x48,
0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x44, 0x65, 0x76, 0x69,
0x63, 0x65, 0x73, 0x20, 0x50, 0x43, 0x41, 0x20, 0x32, 0x30, 0x31, 0x38, 0x30, 0x76, 0x30, 0x10,
0x06, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
0x03, 0x62, 0x00, 0x04, 0x1D, 0xDD, 0x08, 0x02, 0x03, 0x25, 0x75, 0x20, 0xE2, 0x71, 0x8B, 0xAD,
0x28, 0x09, 0x82, 0xE9, 0x06, 0xEE, 0x83, 0xC5, 0x3A, 0x6C, 0x4B, 0x71, 0x92, 0x50, 0x4E, 0x20,
0xE9, 0x72, 0xB4, 0xFC, 0x53, 0x2A, 0xEF, 0x5D, 0xCC, 0x9A, 0xB4, 0xCD, 0x76, 0xB8, 0x94, 0x97,
0x44, 0xB2, 0x71, 0x0E, 0xC9, 0xB1, 0x16, 0x03, 0xA1, 0x65, 0x2B, 0xB9, 0xE8, 0x5D, 0x5F, 0xF2,
0x30, 0x2E, 0xDD, 0xB1, 0x2B, 0x20, 0xFC, 0xBE, 0x00, 0x88, 0xEA, 0x1F, 0xA7, 0x7F, 0x99, 0x84,
0x98, 0x7C, 0x71, 0x3E, 0x4D, 0x34, 0x83, 0x69, 0x9B, 0x08, 0xCB, 0x78, 0xB2, 0x4B, 0xBD, 0xD7,
0x3E, 0xBE, 0x67, 0xA0, 0xA3, 0x82, 0x01, 0xFC, 0x30, 0x82, 0x01, 0xF8, 0x30, 0x10, 0x06, 0x09,
0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x01, 0x04, 0x03, 0x02, 0x01, 0x00, 0x30, 0x1D,
0x06, 0x03, 0x55, 0x1D, 0x0E, 0x04, 0x16, 0x04, 0x14, 0xDA, 0xCA, 0x4B, 0xD0, 0x4C, 0x56, 0x03,
0x27, 0x5F, 0x97, 0xEB, 0x75, 0xA3, 0x02, 0xC3, 0xBF, 0x45, 0x9C, 0xF8, 0xB1, 0x30, 0x65, 0x06,
0x03, 0x55, 0x1D, 0x20, 0x04, 0x5E, 0x30, 0x5C, 0x30, 0x06, 0x06, 0x04, 0x55, 0x1D, 0x20, 0x00,
0x30, 0x52, 0x06, 0x0C, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x4C, 0x83, 0x7D, 0x01, 0x01,
0x30, 0x42, 0x30, 0x40, 0x06, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x34,
0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72, 0x6F,
0x73, 0x6F, 0x66, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73, 0x2F,
0x44, 0x6F, 0x63, 0x73, 0x2F, 0x52, 0x65, 0x70, 0x6F, 0x73, 0x69, 0x74, 0x6F, 0x72, 0x79, 0x2E,
0x68, 0x74, 0x6D, 0x00, 0x30, 0x19, 0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14,
0x02, 0x04, 0x0C, 0x1E, 0x0A, 0x00, 0x53, 0x00, 0x75, 0x00, 0x62, 0x00, 0x43, 0x00, 0x41, 0x30,
0x0B, 0x06, 0x03, 0x55, 0x1D, 0x0F, 0x04, 0x04, 0x03, 0x02, 0x01, 0x86, 0x30, 0x0F, 0x06, 0x03,
0x55, 0x1D, 0x13, 0x01, 0x01, 0xFF, 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xFF, 0x30, 0x1F, 0x06,
0x03, 0x55, 0x1D, 0x23, 0x04, 0x18, 0x30, 0x16, 0x80, 0x14, 0x14, 0xDA, 0x5B, 0xF1, 0x0E, 0x66,
0x47, 0xD1, 0x5D, 0x13, 0x5F, 0x5B, 0x7A, 0xEB, 0xEB, 0x5F, 0x01, 0x08, 0xB5, 0x49, 0x30, 0x7A,
0x06, 0x03, 0x55, 0x1D, 0x1F, 0x04, 0x73, 0x30, 0x71, 0x30, 0x6F, 0xA0, 0x6D, 0xA0, 0x6B, 0x86,
0x69, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72,
0x6F, 0x73, 0x6F, 0x66, 0x74, 0x2E, 0x63, 0x6F, 0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73,
0x2F, 0x63, 0x72, 0x6C, 0x2F, 0x4D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x25, 0x32,
0x30, 0x45, 0x43, 0x43, 0x25, 0x32, 0x30, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x25, 0x32,
0x30, 0x52, 0x6F, 0x6F, 0x74, 0x25, 0x32, 0x30, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
0x61, 0x74, 0x65, 0x25, 0x32, 0x30, 0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x25,
0x32, 0x30, 0x32, 0x30, 0x31, 0x37, 0x2E, 0x63, 0x72, 0x6C, 0x30, 0x81, 0x87, 0x06, 0x08, 0x2B,
0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01, 0x04, 0x7B, 0x30, 0x79, 0x30, 0x77, 0x06, 0x08, 0x2B,
0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x6B, 0x68, 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F,
0x77, 0x77, 0x77, 0x2E, 0x6D, 0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x2E, 0x63, 0x6F,
0x6D, 0x2F, 0x70, 0x6B, 0x69, 0x6F, 0x70, 0x73, 0x2F, 0x63, 0x65, 0x72, 0x74, 0x73, 0x2F, 0x4D,
0x69, 0x63, 0x72, 0x6F, 0x73, 0x6F, 0x66, 0x74, 0x25, 0x32, 0x30, 0x45, 0x43, 0x43, 0x25, 0x32,
0x30, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x25, 0x32, 0x30, 0x52, 0x6F, 0x6F, 0x74, 0x25,
0x32, 0x30, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x25, 0x32, 0x30,
0x41, 0x75, 0x74, 0x68, 0x6F, 0x72, 0x69, 0x74, 0x79, 0x25, 0x32, 0x30, 0x32, 0x30, 0x31, 0x37,
0x2E, 0x63, 0x72, 0x74, 0x30, 0x0A, 0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x03,
0x03, 0x68, 0x00, 0x30, 0x65, 0x02, 0x30, 0x56, 0x2A, 0xAD, 0x72, 0x4C, 0xB9, 0x8C, 0xB3, 0x23,
0x80, 0xF5, 0x5F, 0xF8, 0x21, 0x94, 0x66, 0x0F, 0x76, 0x77, 0xE2, 0x7B, 0x03, 0xDD, 0x30, 0x5E,
0xCB, 0x90, 0xCA, 0x78, 0xE6, 0x0B, 0x2D, 0x12, 0xE5, 0xF7, 0x67, 0x31, 0x58, 0x71, 0xE6, 0xF3,
0x64, 0xC1, 0x04, 0xB3, 0x8B, 0xE9, 0xE2, 0x02, 0x31, 0x00, 0xB9, 0x20, 0x61, 0xB9, 0xD0, 0x5E,
0x3A, 0xA4, 0xA2, 0x8A, 0xFE, 0x1D, 0xFC, 0x27, 0x61, 0x0B, 0x98, 0x16, 0x8C, 0x02, 0x9C, 0x20,
0x7F, 0xEE, 0xF3, 0xCB, 0x1F, 0x0A, 0x37, 0x62, 0xB1, 0x8E, 0xCE, 0xD9, 0x9A, 0x9E, 0xAC, 0xE6,
0x1A, 0xD4, 0xB8, 0xF1, 0xA8, 0x2B, 0xB1, 0xB4, 0x40, 0x9B
};
static void
msg_written_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GError *error = NULL;
GOutputStream *stream = G_OUTPUT_STREAM (source_object);
FpiSsm *ssm = user_data;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (fpi_ssm_get_device (ssm));
g_clear_pointer (&self->msg_out, g_byte_array_unref);
g_assert (self->msg_out == NULL);
if (!g_output_stream_write_all_finish (stream, res, NULL, &error))
{
fpi_ssm_mark_failed (ssm, error);
return;
}
fpi_ssm_next_state (ssm);
}
static void
msg_received_cb (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
{
GError *error = NULL;
GInputStream *stream = G_INPUT_STREAM (source_object);
FpiSsm *ssm = user_data;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (fpi_ssm_get_device (ssm));
gsize read;
g_assert (self->msg_out == NULL);
if (!g_input_stream_read_all_finish (stream, res, &read, &error) ||
read != self->msg_in->len)
{
g_clear_pointer (&self->msg_in, g_byte_array_unref);
if (!error)
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_PROTO,
"Received EOF while reading from test binary.");
fpi_ssm_mark_failed (ssm, error);
return;
}
fpi_ssm_next_state (ssm);
}
enum {
SEND_MESSAGE,
RECV_MESSAGE,
SEND_RECV_STATES
};
static void
send_recv_ssm (FpiSsm *ssm, FpDevice *dev)
{
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
switch (fpi_ssm_get_cur_state (ssm))
{
case SEND_MESSAGE:
g_output_stream_write_all_async (self->proc_stdin,
self->msg_out->data,
self->msg_out->len,
G_PRIORITY_DEFAULT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
msg_written_cb,
ssm);
break;
case RECV_MESSAGE:
g_input_stream_read_all_async (self->proc_stdout,
self->msg_in->data,
self->msg_in->len,
G_PRIORITY_DEFAULT,
fpi_device_get_cancellable (FP_DEVICE (dev)),
msg_received_cb,
ssm);
break;
}
}
static void
connect_2_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
{
g_autoptr(GBytes) recv_data = NULL;
g_autoptr(GBytes) r_d = NULL;
g_autoptr(FpiSdcpClaim) claim = NULL;
g_autoptr(GBytes) mac = NULL;
g_autoptr(GBytes) ca_1_bytes = NULL, ca_2_bytes = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
guint16 cert_size;
if (error)
{
fpi_sdcp_device_connect_complete (FP_SDCP_DEVICE (dev), NULL, NULL, NULL, error);
g_clear_pointer (&self->connect_msg, g_byte_array_unref);
return;
}
memcpy (&cert_size, self->connect_msg->data + 32, 2);
g_byte_array_append (self->connect_msg, self->msg_in->data, self->msg_in->len);
g_clear_pointer (&self->msg_in, g_byte_array_unref);
/* Double check that the size is correct. */
g_assert (self->connect_msg->len == 32 + (2 + cert_size + 65 + 65 + 32 + 64 + 64) + 32);
recv_data = g_byte_array_free_to_bytes (g_steal_pointer (&self->connect_msg));
claim = fpi_sdcp_claim_new ();
r_d = g_bytes_new_from_bytes (recv_data, 0, 32);
claim->cert_m = g_bytes_new_from_bytes (recv_data, 34, cert_size);
claim->pk_d = g_bytes_new_from_bytes (recv_data, 34 + cert_size, 65);
claim->pk_f = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65, 65);
claim->h_f = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65 + 65, 32);
claim->s_m = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65 + 65 + 32, 64);
claim->s_d = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65 + 65 + 32 + 64, 64);
mac = g_bytes_new_from_bytes (recv_data, 34 + cert_size + 65 + 65 + 32 + 64 + 64, 32);
ca_1_bytes = g_bytes_new_static (ca_1, G_N_ELEMENTS (ca_1));
ca_2_bytes = g_bytes_new_static (ca_2, G_N_ELEMENTS (ca_2));
fpi_sdcp_device_set_intermediat_cas (FP_SDCP_DEVICE (dev),
ca_1_bytes,
ca_2_bytes);
fpi_sdcp_device_connect_complete (FP_SDCP_DEVICE (dev), r_d, claim, mac, NULL);
}
static void
connect_1_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
guint16 cert_size;
if (error)
{
fpi_sdcp_device_connect_complete (FP_SDCP_DEVICE (dev), NULL, NULL, NULL, error);
return;
}
g_clear_pointer (&self->connect_msg, g_byte_array_unref);
self->connect_msg = g_steal_pointer (&self->msg_in);
memcpy (&cert_size, self->connect_msg->data + 32, 2);
/* Nothing to send and the rest to receive. */
self->msg_out = g_byte_array_new ();
self->msg_in = g_byte_array_new ();
g_byte_array_set_size (self->msg_in, 32 + (2 + cert_size + 65 + 65 + 32 + 64 + 64) + 32 - self->connect_msg->len);
/* New SSM */
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, SEND_RECV_STATES, "connect 2");
fpi_ssm_start (ssm, connect_2_cb);
}
static void
connect (FpSdcpDevice *dev)
{
g_autoptr(GBytes) r_h = NULL;
g_autoptr(GBytes) pk_h = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
FpiSsm *ssm;
G_DEBUG_HERE ();
g_assert (self->proc);
g_assert (self->connect_msg == NULL);
fpi_sdcp_device_get_connect_data (dev, &r_h, &pk_h);
self->msg_out = g_byte_array_new ();
g_byte_array_append (self->msg_out, (const guint8 *) "C", 1);
g_byte_array_append (self->msg_out,
g_bytes_get_data (r_h, NULL),
g_bytes_get_size (r_h));
g_byte_array_append (self->msg_out,
g_bytes_get_data (pk_h, NULL),
g_bytes_get_size (pk_h));
self->msg_in = g_byte_array_new ();
g_byte_array_set_size (self->msg_in, 34);
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, SEND_RECV_STATES, "connect");
fpi_ssm_start (ssm, connect_1_cb);
}
static void
reconnect_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
{
g_autoptr(GBytes) mac = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
if (error)
{
fpi_sdcp_device_reconnect_complete (FP_SDCP_DEVICE (dev), mac, error);
return;
}
mac = g_byte_array_free_to_bytes (g_steal_pointer (&self->msg_in));
fpi_sdcp_device_reconnect_complete (FP_SDCP_DEVICE (dev), mac, NULL);
}
static void
reconnect (FpSdcpDevice *dev)
{
g_autoptr(GBytes) r_h = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
FpiSsm *ssm;
G_DEBUG_HERE ();
g_assert (self->proc);
fpi_sdcp_device_get_reconnect_data (dev, &r_h);
self->msg_out = g_byte_array_new ();
g_byte_array_append (self->msg_out, (const guint8 *) "R", 1);
g_byte_array_append (self->msg_out,
g_bytes_get_data (r_h, NULL),
g_bytes_get_size (r_h));
self->msg_in = g_byte_array_new ();
g_byte_array_set_size (self->msg_in, 32);
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, SEND_RECV_STATES, "connect 2");
fpi_ssm_start (ssm, reconnect_cb);
}
static void
enroll_begin_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
{
g_autoptr(GBytes) nonce = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
if (error)
{
fpi_sdcp_device_enroll_ready (FP_SDCP_DEVICE (dev), error);
return;
}
nonce = g_byte_array_free_to_bytes (g_steal_pointer (&self->msg_in));
fpi_sdcp_device_enroll_set_nonce (FP_SDCP_DEVICE (dev), nonce);
/* Claim that we completed one enroll step. */
fpi_device_enroll_progress (dev, 1, NULL, NULL);
/* And signal that we are ready to commit. */
fpi_sdcp_device_enroll_ready (FP_SDCP_DEVICE (dev), NULL);
}
static void
enroll_begin (FpSdcpDevice *dev)
{
g_autoptr(GBytes) r_h = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
FpiSsm *ssm;
G_DEBUG_HERE ();
g_assert (self->proc);
fpi_sdcp_device_get_reconnect_data (dev, &r_h);
self->msg_out = g_byte_array_new ();
g_byte_array_append (self->msg_out, (const guint8 *) "E", 1);
/* Expect 32 byte nonce */
self->msg_in = g_byte_array_new ();
g_byte_array_set_size (self->msg_in, 32);
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, SEND_RECV_STATES, "enroll_begin");
fpi_ssm_start (ssm, enroll_begin_cb);
}
static void
enroll_commit_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
{
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
g_clear_pointer (&self->msg_in, g_byte_array_unref);
if (error)
{
fpi_sdcp_device_enroll_ready (FP_SDCP_DEVICE (dev), error);
return;
}
/* Signal that we have committed. We don't expect a response
* from the virtual device (even though that is kind of broken).
*/
fpi_sdcp_device_enroll_commit_complete (FP_SDCP_DEVICE (dev), NULL);
}
static void
enroll_commit (FpSdcpDevice *dev, GBytes *id_in)
{
g_autoptr(GBytes) r_h = NULL;
g_autoptr(GBytes) id = id_in;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
FpiSsm *ssm;
G_DEBUG_HERE ();
g_assert (self->proc);
fpi_sdcp_device_get_reconnect_data (dev, &r_h);
self->msg_out = g_byte_array_new ();
self->msg_in = g_byte_array_new ();
if (id)
{
g_byte_array_append (self->msg_out, (const guint8 *) "F", 1);
g_byte_array_append (self->msg_out,
g_bytes_get_data (id, NULL),
g_bytes_get_size (id));
/* NOTE: No response from device, assume commit works. */
}
else
{
/* Cancel enroll (does not receive a reply) */
g_byte_array_append (self->msg_out, (const guint8 *) "G", 1);
/* NOTE: No response from device, assume cancellation works. */
}
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, SEND_RECV_STATES, "enroll_commit");
fpi_ssm_start (ssm, enroll_commit_cb);
}
static void
identify_cb (FpiSsm *ssm, FpDevice *dev, GError *error)
{
g_autoptr(GBytes) reply = NULL;
g_autoptr(GBytes) id = NULL;
g_autoptr(GBytes) mac = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
if (error)
{
fpi_sdcp_device_identify_complete (FP_SDCP_DEVICE (dev), NULL, NULL, error);
return;
}
reply = g_byte_array_free_to_bytes (g_steal_pointer (&self->msg_in));
id = g_bytes_new_from_bytes (reply, 0, 32);
mac = g_bytes_new_from_bytes (reply, 32, 32);
fpi_sdcp_device_identify_complete (FP_SDCP_DEVICE (self), id, mac, NULL);
}
static void
identify (FpSdcpDevice *dev)
{
g_autoptr(GBytes) nonce = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
FpiSsm *ssm;
G_DEBUG_HERE ();
g_assert (self->proc);
fpi_sdcp_device_get_identify_data (dev, &nonce);
self->msg_out = g_byte_array_new ();
g_byte_array_append (self->msg_out, (const guint8 *) "I", 1);
g_byte_array_append (self->msg_out, g_bytes_get_data (nonce, NULL), g_bytes_get_size (nonce));
/* Expect 64 byte nonce */
self->msg_in = g_byte_array_new ();
g_byte_array_set_size (self->msg_in, 64);
ssm = fpi_ssm_new_full (FP_DEVICE (dev), send_recv_ssm, SEND_RECV_STATES, SEND_RECV_STATES, "identify");
fpi_ssm_start (ssm, identify_cb);
}
static void
probe (FpDevice *dev)
{
g_auto(GStrv) argv = NULL;
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (dev);
GError *error = NULL;
const char *env;
/* We launch the test binary alread at probe time and quit only when
* the object is finalized. This allows testing reconnect properly.
*
* Also, we'll fail probe if something goes wrong executing it.
*/
env = fpi_device_get_virtual_env (FP_DEVICE (self));
if (!g_shell_parse_argv (env, NULL, &argv, &error))
goto out;
self->proc = g_subprocess_newv ((const char * const *) argv,
G_SUBPROCESS_FLAGS_STDIN_PIPE | G_SUBPROCESS_FLAGS_STDOUT_PIPE,
&error);
if (!self->proc)
goto out;
self->proc_stdin = g_object_ref (g_subprocess_get_stdin_pipe (self->proc));
self->proc_stdout = g_object_ref (g_subprocess_get_stdout_pipe (self->proc));
out:
fpi_device_probe_complete (dev, "virtual-sdcp", NULL, error);
}
static void
dev_close (FpDevice *dev)
{
/* No-op, needs to be defined. */
fpi_device_close_complete (dev, NULL);
}
static void
fpi_device_virtual_sdcp_init (FpDeviceVirtualSdcp *self)
{
}
static void
fpi_device_virtual_sdcp_finalize (GObject *obj)
{
FpDeviceVirtualSdcp *self = FPI_DEVICE_VIRTUAL_SDCP (obj);
/* Just kill the subprocess, no need to be graceful here. */
if (self->proc)
g_subprocess_force_exit (self->proc);
g_clear_object (&self->proc);
g_clear_object (&self->proc_stdin);
g_clear_object (&self->proc_stdout);
G_OBJECT_CLASS (fpi_device_virtual_sdcp_parent_class)->finalize (obj);
}
static const FpIdEntry driver_ids[] = {
{ .virtual_envvar = "FP_VIRTUAL_SDCP" },
{ .virtual_envvar = NULL }
};
static void
fpi_device_virtual_sdcp_class_init (FpDeviceVirtualSdcpClass *klass)
{
GObjectClass *obj_class = G_OBJECT_CLASS (klass);
FpDeviceClass *dev_class = FP_DEVICE_CLASS (klass);
FpSdcpDeviceClass *sdcp_class = FP_SDCP_DEVICE_CLASS (klass);
obj_class->finalize = fpi_device_virtual_sdcp_finalize;
dev_class->id = FP_COMPONENT;
dev_class->full_name = "Virtual SDCP device talking to MS test code";
dev_class->type = FP_DEVICE_TYPE_VIRTUAL;
dev_class->id_table = driver_ids;
dev_class->nr_enroll_stages = 1;
/* The SDCP base class may need to override this in the long run */
dev_class->probe = probe;
dev_class->close = dev_close;
sdcp_class->connect = connect;
sdcp_class->reconnect = reconnect;
sdcp_class->enroll_begin = enroll_begin;
sdcp_class->enroll_commit = enroll_commit;
sdcp_class->identify = identify;
}

View File

@@ -140,6 +140,7 @@ typedef enum {
* @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates * @FP_DEVICE_ERROR_DATA_DUPLICATE: Enrolling template duplicates storaged templates
* @FP_DEVICE_ERROR_REMOVED: The device has been removed. * @FP_DEVICE_ERROR_REMOVED: The device has been removed.
* @FP_DEVICE_ERROR_TOO_HOT: The device might be getting too hot * @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 * 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. * such as #G_IO_ERROR or #G_USB_DEVICE_ERROR may also be reported.
@@ -158,6 +159,7 @@ typedef enum {
/* Leave some room to add more DATA related errors */ /* Leave some room to add more DATA related errors */
FP_DEVICE_ERROR_REMOVED = 0x100, FP_DEVICE_ERROR_REMOVED = 0x100,
FP_DEVICE_ERROR_TOO_HOT, FP_DEVICE_ERROR_TOO_HOT,
FP_DEVICE_ERROR_UNTRUSTED,
} FpDeviceError; } FpDeviceError;
GQuark fp_device_retry_quark (void); GQuark fp_device_retry_quark (void);

View File

@@ -605,7 +605,7 @@ fp_print_equal (FpPrint *self, FpPrint *other)
if (g_strcmp0 (self->device_id, other->device_id)) if (g_strcmp0 (self->device_id, other->device_id))
return FALSE; return FALSE;
if (self->type == FPI_PRINT_RAW) if (self->type == FPI_PRINT_RAW || self->type == FPI_PRINT_SDCP)
{ {
return g_variant_equal (self->data, other->data); 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)); g_ptr_array_add (result->prints, g_steal_pointer (&xyt));
} }
} }
else if (type == FPI_PRINT_RAW) else if (type == FPI_PRINT_RAW || type == FPI_PRINT_SDCP)
{ {
g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0); g_autoptr(GVariant) fp_data = g_variant_get_child_value (print_data, 0);

View File

@@ -0,0 +1,58 @@
/*
* 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 "fpi-sdcp-device.h"
#include <nss.h>
#include <keyhi.h>
#include <keythi.h>
#include <pk11pub.h>
typedef struct
{
GError *enroll_pre_commit_error;
/* XXX: Do we want a separate SDCP session object?
*/
GPtrArray *intermediate_cas;
/* Host random for the connection */
guint8 host_random[32];
NSSInitContext *nss_init_context;
PK11SlotInfo *slot;
SECKEYPrivateKey *host_key_private;
SECKEYPublicKey *host_key_public;
/* Master secret is required for reconnects.
* TODO: We probably want to serialize this to disk so it can survive
* fprintd idle shutdown. */
PK11SymKey *master_secret;
PK11SymKey *mac_secret;
} FpSdcpDevicePrivate;
void fpi_sdcp_device_connect (FpSdcpDevice *self);
void fpi_sdcp_device_reconnect (FpSdcpDevice *self);
void fpi_sdcp_device_enroll (FpSdcpDevice *self);
void fpi_sdcp_device_identify (FpSdcpDevice *self);

141
libfprint/fp-sdcp-device.c Normal file
View File

@@ -0,0 +1,141 @@
/*
* 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
*/
#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)
#if 0
/* XXX: We'll very likely want/need some properties on this class. */
enum {
PROP_0,
N_PROPS
};
static GParamSpec *properties[N_PROPS];
#endif
/*******************************************************/
/* Callbacks/vfuncs */
static void
fp_sdcp_device_open (FpDevice *device)
{
FpSdcpDevice *self = FP_SDCP_DEVICE (device);
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
/* Try a reconnect if we still have the mac secret. */
if (priv->mac_secret)
fpi_sdcp_device_reconnect (self);
else
fpi_sdcp_device_connect (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->intermediate_cas, g_ptr_array_unref);
g_clear_pointer (&priv->slot, PK11_FreeSlot);
g_clear_pointer (&priv->host_key_private, SECKEY_DestroyPrivateKey);
g_clear_pointer (&priv->host_key_public, SECKEY_DestroyPublicKey);
g_clear_pointer (&priv->master_secret, PK11_FreeSymKey);
g_clear_pointer (&priv->mac_secret, PK11_FreeSymKey);
g_clear_pointer (&priv->nss_init_context, NSS_ShutdownContext);
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)
{
switch (prop_id)
{
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->constructed = fp_sdcp_device_constructed;
fp_device_class->open = fp_sdcp_device_open;
fp_device_class->enroll = fp_sdcp_device_enroll;
fp_device_class->verify = fp_sdcp_device_identify;
fp_device_class->identify = fp_sdcp_device_identify;
#if 0
g_object_class_install_properties (object_class, N_PROPS, properties);
#endif
}
static void
fp_sdcp_device_init (FpSdcpDevice *self)
{
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
priv->intermediate_cas = g_ptr_array_new_with_free_func ((GDestroyNotify) g_bytes_unref);
}

View File

@@ -0,0 +1,29 @@
/*
* 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

View File

@@ -185,6 +185,9 @@ fpi_device_error_new (FpDeviceError error)
case FP_DEVICE_ERROR_TOO_HOT: case FP_DEVICE_ERROR_TOO_HOT:
msg = "Device disabled to prevent overheating."; msg = "Device disabled to prevent overheating.";
case FP_DEVICE_ERROR_UNTRUSTED:
msg = "Could not verify integrity of the device, it cannot be trusted!";
break; break;
default: default:

View File

@@ -11,11 +11,13 @@ G_BEGIN_DECLS
* @FPI_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment * @FPI_PRINT_UNDEFINED: Undefined type, this happens prior to enrollment
* @FPI_PRINT_RAW: A raw print where the data is directly compared * @FPI_PRINT_RAW: A raw print where the data is directly compared
* @FPI_PRINT_NBIS: NBIS minutiae comparison * @FPI_PRINT_NBIS: NBIS minutiae comparison
* @FPI_PRINT_SDCP: Print from an SDCP conforming device
*/ */
typedef enum { typedef enum {
FPI_PRINT_UNDEFINED = 0, FPI_PRINT_UNDEFINED = 0,
FPI_PRINT_RAW, FPI_PRINT_RAW,
FPI_PRINT_NBIS, FPI_PRINT_NBIS,
FPI_PRINT_SDCP,
} FpiPrintType; } FpiPrintType;
/** /**

1469
libfprint/fpi-sdcp-device.c Normal file

File diff suppressed because it is too large Load Diff

142
libfprint/fpi-sdcp-device.h Normal file
View File

@@ -0,0 +1,142 @@
/*
* 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 <glib-2.0/glib.h>
#include "fpi-device.h"
#include "fp-sdcp-device.h"
/**
* FpiSdcpClaim:
* @cert_m: The per-model ECDSA certificate (x509 ASN.1 DER encoded)
* @pk_d: The device public key (65 bytes)
* @pk_f: The firmware public key (65 bytes)
* @h_f: The firmware hash
* @s_m: Signature over @pk_d using the per-model private key (64 bytes)
* @s_d: Signature over h_f and pk_f using the device private key (64 bytes)
*
* 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 *cert_m;
GBytes *pk_d;
GBytes *pk_f;
GBytes *h_f;
GBytes *s_m;
GBytes *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:
* @connect: Establish SDCP connection. Similar to open in #FpDeviceClass
* but called connect to mirror the SDCP specification.
* @reconnect: Perform a faster reconnect. Drivers do not need to provide this
* function. If reconnect fails, then a normal connect will be tried.
* @enroll_begin: Start the enrollment procedure. In the absence of an error,
* the driver must call fpi_sdcp_device_enroll_set_nonce() at any point. It
* also must report enrollment progress using fpi_device_enroll_progress().
* It should also store available metadata about the print in device memory.
* The operation is completed with fpi_sdcp_device_enroll_ready().
* @enroll_commit: Complete the enrollment procedure. This commits the newly
* enrolled print to the device memory. Will only be called if enroll_begin
* succeeded. The passed id may be %NULL, in that case the driver must
* abort the enrollment process. id is owned by the base class and remains
* valid throughout the operation.
* @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.
*
* 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;
void (*connect) (FpSdcpDevice *dev);
void (*reconnect) (FpSdcpDevice *dev);
void (*close) (FpSdcpDevice *dev);
void (*enroll_begin) (FpSdcpDevice *dev);
void (*enroll_commit) (FpSdcpDevice *dev,
GBytes *id);
void (*identify) (FpSdcpDevice *dev);
};
void fpi_sdcp_device_set_intermediat_cas (FpSdcpDevice *self,
GBytes *ca_1,
GBytes *ca_2);
void fpi_sdcp_device_get_connect_data (FpSdcpDevice *self,
GBytes **r_h,
GBytes **pk_h);
void fpi_sdcp_device_connect_complete (FpSdcpDevice *self,
GBytes *r_d,
FpiSdcpClaim *claim,
GBytes *mac,
GError *error);
void fpi_sdcp_device_get_reconnect_data (FpSdcpDevice *self,
GBytes **r_h);
void fpi_sdcp_device_reconnect_complete (FpSdcpDevice *self,
GBytes *mac,
GError *error);
void fpi_sdcp_device_enroll_set_nonce (FpSdcpDevice *self,
GBytes *nonce);
void fpi_sdcp_device_enroll_ready (FpSdcpDevice *self,
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_identify_retry (FpSdcpDevice *self,
GError *error);
void fpi_sdcp_device_identify_complete (FpSdcpDevice *self,
GBytes *id,
GBytes *mac,
GError *error);

View File

@@ -135,6 +135,8 @@ driver_sources = {
[ 'drivers/virtual-device.c' ], [ 'drivers/virtual-device.c' ],
'virtual_device_storage' : 'virtual_device_storage' :
[ 'drivers/virtual-device-storage.c' ], [ 'drivers/virtual-device-storage.c' ],
'virtual_sdcp' :
[ 'drivers/virtual-sdcp.c' ],
'synaptics' : 'synaptics' :
[ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ], [ 'drivers/synaptics/synaptics.c', 'drivers/synaptics/bmkt_message.c' ],
'goodixmoc' : 'goodixmoc' :
@@ -142,6 +144,8 @@ driver_sources = {
} }
helper_sources = { helper_sources = {
'sdcp' :
[ 'fp-sdcp-device.c', 'fpi-sdcp-device.c' ],
'aeslib' : 'aeslib' :
[ 'drivers/aeslib.c' ], [ 'drivers/aeslib.c' ],
'aesx660' : 'aesx660' :

View File

@@ -96,8 +96,8 @@ virtual_drivers = [
'virtual_image', 'virtual_image',
'virtual_device', 'virtual_device',
'virtual_device_storage', 'virtual_device_storage',
'virtual_sdcp',
] ]
default_drivers = [ default_drivers = [
'upektc_img', 'upektc_img',
'vfs5011', 'vfs5011',
@@ -159,6 +159,7 @@ driver_helper_mapping = {
'virtual_image' : [ 'virtual' ], 'virtual_image' : [ 'virtual' ],
'virtual_device' : [ 'virtual' ], 'virtual_device' : [ 'virtual' ],
'virtual_device_storage' : [ 'virtual' ], 'virtual_device_storage' : [ 'virtual' ],
'virtual_sdcp' : [ 'sdcp' ],
} }
driver_helpers = [] driver_helpers = []
@@ -217,6 +218,13 @@ foreach i : driver_helpers
error('nss is required for @0@ and possibly others'.format(driver)) error('nss is required for @0@ and possibly others'.format(driver))
endif endif
optional_deps += nss_dep
elif i == 'sdcp'
nss_dep = dependency('nss', version: '>=3.55', required: false)
if not nss_dep.found()
error('nss >=3.55 is required for SDCP support (@0@ and possibly others)'.format(driver))
endif
optional_deps += nss_dep optional_deps += nss_dep
elif i == 'udev' elif i == 'udev'
install_udev_rules = true install_udev_rules = true

View File

@@ -30,3 +30,8 @@ option('doc',
description: 'Whether to build the API documentation', description: 'Whether to build the API documentation',
type: 'boolean', type: 'boolean',
value: true) value: true)
option('sdcp_virt_binary',
description: 'Path to virtual SDCP test binary, please refer to CI for more details.',
type: 'string',
value: '')

View File

@@ -12,6 +12,9 @@ envs.prepend('LD_LIBRARY_PATH', join_paths(meson.build_root(), 'libfprint'))
# random numbers rather than proper ones) # random numbers rather than proper ones)
envs.set('FP_DEVICE_EMULATION', '1') envs.set('FP_DEVICE_EMULATION', '1')
# Path to SDCP virtual device binary, only used for virtual-sdcp test
envs.set('SDCP_VIRT_BINARY', get_option('sdcp_virt_binary'))
# Set a colon-separated list of native drivers we enable in tests # Set a colon-separated list of native drivers we enable in tests
envs.set('FP_DRIVERS_WHITELIST', ':'.join([ envs.set('FP_DRIVERS_WHITELIST', ':'.join([
'virtual_image', 'virtual_image',
@@ -88,6 +91,7 @@ if get_option('introspection')
suite: ut_suite, suite: ut_suite,
depends: libfprint_typelib, depends: libfprint_typelib,
env: envs, env: envs,
workdir: meson.current_source_dir(),
) )
endforeach endforeach
else else
@@ -98,6 +102,46 @@ if get_option('introspection')
endif endif
endforeach endforeach
if 'virtual_sdcp' in drivers and get_option('sdcp_virt_binary') != ''
python3 = find_program('python3')
unittest_inspector = find_program('unittest_inspector.py')
base_args = files('virtual-sdcp.py')
suite = []
r = run_command(unittest_inspector, files('virtual-sdcp.py'))
unit_tests = r.stdout().strip().split('\n')
if r.returncode() == 0 and unit_tests.length() > 0
suite += 'virtual-sdcp'
else
unit_tests = ['virtual-sdcp']
endif
sdcp_envs = envs
sdcp_envs.set('FP_DEVICE_EMULATION', '0')
foreach ut: unit_tests
ut_suite = suite
ut_args = base_args
if unit_tests.length() > 1
ut_args += ut
ut_suite += ut.split('.')[0]
endif
test(ut,
python3,
args: ut_args,
suite: ut_suite,
depends: libfprint_typelib,
env: sdcp_envs,
workdir: meson.current_source_dir(),
)
endforeach
else
test('virtual-sdcp',
find_program('sh'),
args: ['-c', 'exit 77']
)
endif
foreach driver_test: drivers_tests foreach driver_test: drivers_tests
driver_name = driver_test.split('-')[0] driver_name = driver_test.split('-')[0]
driver_envs = envs driver_envs = envs
@@ -109,6 +153,7 @@ if get_option('introspection')
find_program('umockdev-test.py'), find_program('umockdev-test.py'),
args: join_paths(meson.current_source_dir(), driver_test), args: join_paths(meson.current_source_dir(), driver_test),
env: driver_envs, env: driver_envs,
workdir: meson.current_source_dir(),
suite: ['drivers'], suite: ['drivers'],
timeout: 15, timeout: 15,
depends: libfprint_typelib, depends: libfprint_typelib,

BIN
tests/sdcp-key-db/cert9.db Normal file

Binary file not shown.

BIN
tests/sdcp-key-db/key4.db Normal file

Binary file not shown.

144
tests/virtual-sdcp.py Normal file
View File

@@ -0,0 +1,144 @@
#!/usr/bin/env python3
import sys
try:
import gi
import os
from gi.repository import GLib, Gio
import unittest
import subprocess
import shutil
import tempfile
except Exception as e:
print("Missing dependencies: %s" % str(e))
sys.exit(77)
FPrint = None
# Re-run the test with the passed wrapper if set
wrapper = os.getenv('LIBFPRINT_TEST_WRAPPER')
if wrapper:
wrap_cmd = wrapper.split(' ') + [sys.executable, os.path.abspath(__file__)] + \
sys.argv[1:]
os.unsetenv('LIBFPRINT_TEST_WRAPPER')
sys.exit(subprocess.check_call(wrap_cmd))
# 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 VirtualSDCP(unittest.TestCase):
@classmethod
def setUpClass(cls):
os.environ['FP_VIRTUAL_SDCP'] = os.environ['SDCP_VIRT_BINARY']
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):
pass
def tearDown(self):
pass
def enroll(self, progress_cb=None):
# Enroll another print
template = FPrint.Print.new(self.dev)
template.props.finger = FPrint.Finger.LEFT_THUMB
template.props.username = "testuser"
template.props.description = "test print"
datetime = GLib.DateTime.new_now_local()
date = GLib.Date()
date.set_dmy(*datetime.get_ymd()[::-1])
template.props.enroll_date = date
return self.dev.enroll_sync(template, None, progress_cb, None)
def test_connect(self):
self.dev.open_sync()
self.dev.close_sync()
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.open_sync()
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 == '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()
self.dev.close_sync()
GLib.log_remove_handler('libfprint-sdcp_device', handler_id)
assert success[0]
def test_enroll(self):
self.dev.open_sync()
# Must return a print
assert isinstance(self.enroll(), FPrint.Print)
self.dev.close_sync()
def test_verify(self):
self.dev.open_sync()
# Enroll a new print (will be the last), check that it verifies
p = self.enroll()
match, dev_print = self.dev.verify_sync(p)
assert match
# The returned "device" print is identical
assert p.equal(dev_print)
# We can do the same with it
match, dev_print2 = self.dev.verify_sync(dev_print)
assert match
# Now, enroll a new print, causing the old one to not match anymore
# (the device always claims to see the last enrolled print).
self.enroll()
match, dev_print = self.dev.verify_sync(p)
assert match is False
self.dev.close_sync()
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)
# avoid writing to stderr
unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, verbosity=2))