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.
This commit is contained in:
Benjamin Berg 2020-11-03 13:44:55 +01:00
parent 4f100956ac
commit d6dc3403d8
2 changed files with 84 additions and 19 deletions

View file

@ -23,6 +23,7 @@
#include <sechash.h> #include <sechash.h>
#include <cert.h> #include <cert.h>
#include "fpi-compat.h"
#include "fp-sdcp-device-private.h" #include "fp-sdcp-device-private.h"
#include "fpi-sdcp-device.h" #include "fpi-sdcp-device.h"
#include "fpi-print.h" #include "fpi-print.h"
@ -156,6 +157,47 @@ fp_sdcp_device_get_instance_private (FpSdcpDevice *self)
g_type_class_get_instance_private_offset (sdcp_class)); g_type_class_get_instance_private_offset (sdcp_class));
} }
/**
* fpi_sdcp_generate_random:
* @buffer: Buffer to place random bytes into
* @len: Number of bytes to generate
* @error: Error out
*
* Returns: #TRUE on success
**/
FP_GNUC_ACCESS (write_only, 1, 2)
static gboolean
fpi_sdcp_generate_random (guint8 *buffer, gsize len, GError **error)
{
/* Just use a counter in emulation mode. Not random, but all
* we need is something predictable and not repeating immediately.
*/
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
{
static guint8 emulation_rand = 0;
gsize i;
for (i = 0; i < len; i++)
{
buffer[i] = emulation_rand;
emulation_rand += 1;
}
return TRUE;
}
/* Generating random numbers is basic enough to assume it works */
if (PK11_GenerateRandom (buffer, len) != SECSuccess)
{
g_propagate_error (error,
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Error generating random numbers using NSS!"));
return FALSE;
}
return TRUE;
}
/** /**
* fpi_sdcp_kdf: * fpi_sdcp_kdf:
* @self: The #FpSdcpDevice * @self: The #FpSdcpDevice
@ -236,7 +278,6 @@ fpi_sdcp_kdf (FpSdcpDevice *self,
data_param[kdf_params.ulNumberOfDataParams].ulValueLen = sizeof (length_format); data_param[kdf_params.ulNumberOfDataParams].ulValueLen = sizeof (length_format);
kdf_params.ulNumberOfDataParams += 1; kdf_params.ulNumberOfDataParams += 1;
/* TODO: support a second key out (may be discarded) */
kdf_params.ulAdditionalDerivedKeys = 0; kdf_params.ulAdditionalDerivedKeys = 0;
kdf_params.pAdditionalDerivedKeys = NULL; kdf_params.pAdditionalDerivedKeys = NULL;
if (out_key_2) if (out_key_2)
@ -362,6 +403,7 @@ fpi_sdcp_device_connect (FpSdcpDevice *self)
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self); FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
PLArenaPool *arena = NULL; PLArenaPool *arena = NULL;
ECParams ec_parameters = { NULL }; ECParams ec_parameters = { NULL };
GError *error = NULL;
SECStatus r = SECSuccess; SECStatus r = SECSuccess;
@ -397,7 +439,30 @@ fpi_sdcp_device_connect (FpSdcpDevice *self)
arena = PORT_NewArena (NSS_FREEBL_DEFAULT_CHUNKSIZE); arena = PORT_NewArena (NSS_FREEBL_DEFAULT_CHUNKSIZE);
EC_FillParams (arena, &SDCPECParamsDER, &ec_parameters); EC_FillParams (arena, &SDCPECParamsDER, &ec_parameters);
r = EC_NewKey (&ec_parameters, &priv->host_key_private);
/* Just use a counter in emulation mode. Not random, but all
* we need is something predictable and not repeating immediately.
*/
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
{
/* ECDSA Known Seed info for curves nistp256 and nistk283 */
static const PRUint8 ecdsa_known_seed[] = {
0x6a, 0x9b, 0xf6, 0xf7, 0xce, 0xed, 0x79, 0x11,
0xf0, 0xc7, 0xc8, 0x9a, 0xa5, 0xd1, 0x57, 0xb1,
0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc,
0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f
};
r = EC_NewKeyFromSeed (&ec_parameters,
&priv->host_key_private,
ecdsa_known_seed,
sizeof (ecdsa_known_seed));
}
else
{
r = EC_NewKey (&ec_parameters, &priv->host_key_private);
}
PORT_FreeArena (arena, FALSE); PORT_FreeArena (arena, FALSE);
arena = NULL; arena = NULL;
@ -405,9 +470,13 @@ fpi_sdcp_device_connect (FpSdcpDevice *self)
goto nss_error; goto nss_error;
/* SDCP Connect: 3.ii. Generate host random */ /* SDCP Connect: 3.ii. Generate host random */
r = PK11_GenerateRandom (priv->host_random, sizeof (priv->host_random)); if (!fpi_sdcp_generate_random (priv->host_random, sizeof (priv->host_random), &error))
if (r != SECSuccess) {
goto nss_error; fpi_sdcp_device_connect_complete (self,
NULL, NULL, NULL,
error);
return;
}
/* SDCP Connect: 3.iii. Send the Connect message */ /* SDCP Connect: 3.iii. Send the Connect message */
cls->connect (self); cls->connect (self);
@ -428,16 +497,13 @@ fpi_sdcp_device_reconnect (FpSdcpDevice *self)
{ {
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self); FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self); FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
SECStatus r; GError *error = NULL;
/* SDCP Reconnect: 2.i. Generate host random */ /* SDCP Reconnect: 2.i. Generate host random */
r = PK11_GenerateRandom (priv->host_random, sizeof (priv->host_random)); if (!fpi_sdcp_generate_random (priv->host_random, sizeof (priv->host_random), &error))
if (r != SECSuccess)
{ {
fpi_sdcp_device_reconnect_complete (self, fpi_sdcp_device_reconnect_complete (self, NULL, error);
NULL, return;
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Error calling NSS crypto routine: %d", r));
} }
/* SDCP Reconnect: 2.ii. Send the Reconnect message */ /* SDCP Reconnect: 2.ii. Send the Reconnect message */
@ -473,7 +539,7 @@ fpi_sdcp_device_identify (FpSdcpDevice *self)
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self); FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self); FpSdcpDeviceClass *cls = FP_SDCP_DEVICE_GET_CLASS (self);
FpiDeviceAction action; FpiDeviceAction action;
SECStatus r; GError *error = NULL;
g_return_if_fail (FP_IS_SDCP_DEVICE (self)); g_return_if_fail (FP_IS_SDCP_DEVICE (self));
action = fpi_device_get_current_action (FP_DEVICE (self)); action = fpi_device_get_current_action (FP_DEVICE (self));
@ -481,12 +547,9 @@ fpi_sdcp_device_identify (FpSdcpDevice *self)
g_return_if_fail (action == FPI_DEVICE_ACTION_IDENTIFY || action == FPI_DEVICE_ACTION_VERIFY); g_return_if_fail (action == FPI_DEVICE_ACTION_IDENTIFY || action == FPI_DEVICE_ACTION_VERIFY);
/* Generate a new nonce. */ /* Generate a new nonce. */
r = PK11_GenerateRandom (priv->host_random, sizeof (priv->host_random)); if (!fpi_sdcp_generate_random (priv->host_random, sizeof (priv->host_random), &error))
if (r != SECSuccess)
{ {
fpi_device_action_error (FP_DEVICE (self), fpi_device_action_error (FP_DEVICE (self), error);
fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL,
"Error calling NSS crypto routine: %d", r));
return; return;
} }

View file

@ -100,6 +100,8 @@ if get_option('introspection')
unit_tests = ['virtual-sdcp'] unit_tests = ['virtual-sdcp']
endif endif
sdcp_envs = envs
sdcp_envs.set('FP_DEVICE_EMULATION', '0')
foreach ut: unit_tests foreach ut: unit_tests
ut_suite = suite ut_suite = suite
ut_args = base_args ut_args = base_args
@ -112,7 +114,7 @@ if get_option('introspection')
args: ut_args, args: ut_args,
suite: ut_suite, suite: ut_suite,
depends: libfprint_typelib, depends: libfprint_typelib,
env: envs, env: sdcp_envs,
) )
endforeach endforeach
else else