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
This commit is contained in:
parent
8d83e5eb38
commit
77400b7a60
9 changed files with 1777 additions and 1 deletions
|
@ -85,6 +85,12 @@ FP_TYPE_IMAGE_DEVICE
|
|||
FpImageDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-sdcp-device</FILE>
|
||||
FP_TYPE_SDCP_DEVICE
|
||||
FpSdcpDevice
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>fp-print</FILE>
|
||||
FP_TYPE_PRINT
|
||||
|
@ -186,6 +192,26 @@ fpi_image_device_image_captured
|
|||
fpi_image_device_retry_scan
|
||||
</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>
|
||||
<FILE>fpi-log</FILE>
|
||||
fp_dbg
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
<xi:include href="xml/fp-context.xml"/>
|
||||
<xi:include href="xml/fp-device.xml"/>
|
||||
<xi:include href="xml/fp-image-device.xml"/>
|
||||
<xi:include href="xml/fp-sdcp-device.xml"/>
|
||||
<xi:include href="xml/fp-print.xml"/>
|
||||
<xi:include href="xml/fp-image.xml"/>
|
||||
</part>
|
||||
|
@ -38,6 +39,7 @@
|
|||
<title>Device methods for drivers</title>
|
||||
<xi:include href="xml/fpi-device.xml"/>
|
||||
<xi:include href="xml/fpi-image-device.xml"/>
|
||||
<xi:include href="xml/fpi-sdcp-device.xml"/>
|
||||
</chapter>
|
||||
|
||||
<chapter id="driver-helpers">
|
||||
|
|
58
libfprint/fp-sdcp-device-private.h
Normal file
58
libfprint/fp-sdcp-device-private.h
Normal 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
141
libfprint/fp-sdcp-device.c
Normal 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);
|
||||
}
|
29
libfprint/fp-sdcp-device.h
Normal file
29
libfprint/fp-sdcp-device.h
Normal 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
|
1369
libfprint/fpi-sdcp-device.c
Normal file
1369
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
142
libfprint/fpi-sdcp-device.h
Normal 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);
|
|
@ -130,6 +130,8 @@ driver_sources = {
|
|||
}
|
||||
|
||||
helper_sources = {
|
||||
'sdcp' :
|
||||
[ 'fp-sdcp-device.c', 'fpi-sdcp-device.c' ],
|
||||
'aeslib' :
|
||||
[ 'drivers/aeslib.c' ],
|
||||
'aesx660' :
|
||||
|
@ -199,6 +201,13 @@ foreach i : helpers + drivers
|
|||
error('nss is required for uru4000')
|
||||
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
|
||||
else
|
||||
deps = []
|
||||
|
|
Loading…
Reference in a new issue