sdcp-device: Use a key DB for testing

This commit is contained in:
Benjamin Berg 2020-11-03 18:12:33 +01:00
parent d6dc3403d8
commit 64bbdc81a2
7 changed files with 93 additions and 71 deletions

View file

@ -22,11 +22,6 @@
#include "fpi-sdcp-device.h" #include "fpi-sdcp-device.h"
#include <nss.h> #include <nss.h>
#pragma GCC diagnostic push
/* blapi.h is missing a void in a function declaration with no arguments */
#pragma GCC diagnostic ignored "-Wstrict-prototypes"
#include <blapi.h>
#pragma GCC diagnostic pop
#include <keyhi.h> #include <keyhi.h>
#include <keythi.h> #include <keythi.h>
#include <pk11pub.h> #include <pk11pub.h>
@ -41,11 +36,12 @@ typedef struct
GPtrArray *intermediate_cas; GPtrArray *intermediate_cas;
/* Host random for the connection */ /* Host random for the connection */
guint8 host_random[32]; guint8 host_random[32];
NSSInitContext *nss_init_context; NSSInitContext *nss_init_context;
PK11SlotInfo *slot; PK11SlotInfo *slot;
ECPrivateKey *host_key_private; SECKEYPrivateKey *host_key_private;
SECKEYPublicKey *host_key_public;
/* Master secret is required for reconnects. /* Master secret is required for reconnects.
* TODO: We probably want to serialize this to disk so it can survive * TODO: We probably want to serialize this to disk so it can survive

View file

@ -84,12 +84,11 @@ fp_sdcp_device_finalize (GObject *object)
g_clear_pointer (&priv->intermediate_cas, g_ptr_array_unref); g_clear_pointer (&priv->intermediate_cas, g_ptr_array_unref);
g_clear_pointer (&priv->slot, PK11_FreeSlot); 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->master_secret, PK11_FreeSymKey);
g_clear_pointer (&priv->mac_secret, PK11_FreeSymKey); g_clear_pointer (&priv->mac_secret, PK11_FreeSymKey);
g_clear_pointer (&priv->nss_init_context, NSS_ShutdownContext); g_clear_pointer (&priv->nss_init_context, NSS_ShutdownContext);
if (priv->host_key_private)
PORT_FreeArena (priv->host_key_private->ecParams.arena, TRUE);
priv->host_key_private = NULL;
G_OBJECT_CLASS (fp_sdcp_device_parent_class)->finalize (object); G_OBJECT_CLASS (fp_sdcp_device_parent_class)->finalize (object);
} }

View file

@ -401,8 +401,6 @@ fpi_sdcp_device_connect (FpSdcpDevice *self)
G_GNUC_UNUSED g_autofree void * ec_params_data = NULL; G_GNUC_UNUSED g_autofree void * ec_params_data = NULL;
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);
PLArenaPool *arena = NULL;
ECParams ec_parameters = { NULL };
GError *error = NULL; GError *error = NULL;
SECStatus r = SECSuccess; SECStatus r = SECSuccess;
@ -425,46 +423,85 @@ fpi_sdcp_device_connect (FpSdcpDevice *self)
goto nss_error; goto nss_error;
g_clear_pointer (&priv->slot, PK11_FreeSlot); g_clear_pointer (&priv->slot, PK11_FreeSlot);
if (priv->host_key_private) g_clear_pointer (&priv->host_key_private, SECKEY_DestroyPrivateKey);
PORT_FreeArena (priv->host_key_private->ecParams.arena, TRUE); g_clear_pointer (&priv->host_key_public, SECKEY_DestroyPublicKey);
priv->host_key_private = NULL; priv->host_key_private = NULL;
/* Create a slot for PK11 operation */
priv->slot = PK11_GetBestSlot (CKM_EC_KEY_PAIR_GEN, NULL);
if (priv->slot == NULL)
goto nss_error;
/* SDCP Connect: 3.i. Generate an ephemeral ECDH key pair */ /* SDCP Connect: 3.i. Generate an ephemeral ECDH key pair */
/* Look up the OID data for our curve. */ /* Look up the OID data for our curve. */
arena = PORT_NewArena (NSS_FREEBL_DEFAULT_CHUNKSIZE);
EC_FillParams (arena, &SDCPECParamsDER, &ec_parameters);
/* Just use a counter in emulation mode. Not random, but all /* Just use a counter in emulation mode. Not random, but all
* we need is something predictable and not repeating immediately. * we need is something predictable and not repeating immediately.
*/ */
if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0) if (g_strcmp0 (g_getenv ("FP_DEVICE_EMULATION"), "1") == 0)
{ {
/* ECDSA Known Seed info for curves nistp256 and nistk283 */ /* To generate, use the #if 0 code below and remove the readOnly flag */
static const PRUint8 ecdsa_known_seed[] = { priv->slot = SECMOD_OpenUserDB ("configdir='sdcp-key-db' tokenDescription='libfprint CI testing' flags=readOnly");
0x6a, 0x9b, 0xf6, 0xf7, 0xce, 0xed, 0x79, 0x11, if (!priv->slot)
0xf0, 0xc7, 0xc8, 0x9a, 0xa5, 0xd1, 0x57, 0xb1, {
0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc, g_message ("Could not open key DB for testing");
0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f exit (77);
}; }
r = EC_NewKeyFromSeed (&ec_parameters, #if 0
&priv->host_key_private, if (PK11_NeedUserInit (priv->slot))
ecdsa_known_seed, if (PK11_InitPin (priv->slot, "", "") != SECSuccess)
sizeof (ecdsa_known_seed)); goto nss_error;
if (priv->slot == NULL)
goto nss_error;
g_debug ("logged in: %i, need: %i", PK11_IsLoggedIn (priv->slot, NULL), PK11_NeedLogin (priv->slot));
g_debug ("read only: %i", PK11_IsReadOnly (priv->slot));
g_debug ("need user init: %i", PK11_NeedUserInit (priv->slot));
//PK11_SetPasswordFunc (pwfunc);
/* SDCP Connect: 3.i. Generate an ephemeral ECDH key pair */
/* Look up the OID data for our curve. */
oid_data = SECOID_FindOIDByTag (SEC_OID_SECG_EC_SECP256R1);
if (!oid_data)
goto nss_error;
priv->host_key_private = PK11_GenerateKeyPair (priv->slot, CKM_EC_KEY_PAIR_GEN,
(SECItem *) &SDCPECParamsDER,
&priv->host_key_public,
TRUE, FALSE,
NULL);
PK11_SetPrivateKeyNickname (priv->host_key_private, "CI testing");
PK11_SetPublicKeyNickname (priv->host_key_public, "CI testing");
#else
g_assert (!PK11_NeedUserInit (priv->slot));
g_assert (PK11_IsReadOnly (priv->slot));
SECKEYPrivateKeyList *priv_key_list = NULL;
SECKEYPublicKeyList *pub_key_list = NULL;
priv_key_list = PK11_ListPrivKeysInSlot (priv->slot, (char *) "CI testing", NULL);
pub_key_list = PK11_ListPublicKeysInSlot (priv->slot, (char *) "CI testing");
g_assert (priv_key_list != NULL && pub_key_list != NULL);
g_assert (!PR_CLIST_IS_EMPTY (&priv_key_list->list) && !PR_CLIST_IS_EMPTY (&pub_key_list->list));
priv->host_key_private = SECKEY_CopyPrivateKey (((SECKEYPrivateKeyListNode *) PR_LIST_HEAD (&priv_key_list->list))->key);
priv->host_key_public = SECKEY_CopyPublicKey (((SECKEYPublicKeyListNode *) PR_LIST_HEAD (&pub_key_list->list))->key);
SECKEY_DestroyPrivateKeyList (priv_key_list);
SECKEY_DestroyPublicKeyList (pub_key_list);
#endif
} }
else else
{ {
r = EC_NewKey (&ec_parameters, &priv->host_key_private); /* Create a slot for PK11 operation */
} priv->slot = PK11_GetBestSlot (CKM_EC_KEY_PAIR_GEN, NULL);
if (priv->slot == NULL)
goto nss_error;
PORT_FreeArena (arena, FALSE); priv->host_key_private = PK11_GenerateKeyPair (priv->slot, CKM_EC_KEY_PAIR_GEN,
arena = NULL; (SECItem *) &SDCPECParamsDER,
&priv->host_key_public,
FALSE, TRUE,
NULL);
}
if (r != SECSuccess) if (r != SECSuccess)
goto nss_error; goto nss_error;
@ -602,8 +639,8 @@ fpi_sdcp_device_get_connect_data (FpSdcpDevice *self,
*r_h = g_bytes_new (priv->host_random, sizeof (priv->host_random)); *r_h = g_bytes_new (priv->host_random, sizeof (priv->host_random));
g_assert (priv->host_key_private->publicValue.len == 65); g_assert (priv->host_key_public->u.ec.publicValue.len == 65);
*pk_h = g_bytes_new (priv->host_key_private->publicValue.data, priv->host_key_private->publicValue.len); *pk_h = g_bytes_new (priv->host_key_public->u.ec.publicValue.data, priv->host_key_public->u.ec.publicValue.len);
} }
/** /**
@ -831,14 +868,13 @@ fpi_sdcp_device_connect_complete (FpSdcpDevice *self,
g_autoptr(GBytes) claim_hash_bytes = NULL; g_autoptr(GBytes) claim_hash_bytes = NULL;
g_autoptr(GBytes) claim_mac = NULL; g_autoptr(GBytes) claim_mac = NULL;
FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self); FpSdcpDevicePrivate *priv = fp_sdcp_device_get_instance_private (self);
SECItem pk_f; SECKEYPublicKey firmware_key_public = { 0, };
SECKEYPublicKey device_key_public = { 0, }; SECKEYPublicKey device_key_public = { 0, };
SECKEYPublicKey *model_key_public = NULL; SECKEYPublicKey *model_key_public = NULL;
HASHContext *hash_ctx; HASHContext *hash_ctx;
guint8 hash_out[SHA256_LENGTH]; guint8 hash_out[SHA256_LENGTH];
guint hash_len = 0; guint hash_len = 0;
FpiDeviceAction action; FpiDeviceAction action;
SECItem a_raw = { 0 };
PK11SymKey *a = NULL; PK11SymKey *a = NULL;
PK11SymKey *enc_secret = NULL; PK11SymKey *enc_secret = NULL;
gsize length; gsize length;
@ -879,30 +915,24 @@ fpi_sdcp_device_connect_complete (FpSdcpDevice *self,
/* Device key is of same type as host key */ /* Device key is of same type as host key */
g_assert (g_bytes_get_size (claim->pk_f) == 65); g_assert (g_bytes_get_size (claim->pk_f) == 65);
pk_f.len = 65; firmware_key_public.keyType = ecKey;
pk_f.data = (guint8 *) g_bytes_get_data (claim->pk_f, NULL); firmware_key_public.u.ec.DEREncodedParams = SDCPECParamsDER;
firmware_key_public.u.ec.publicValue.len = 65;
firmware_key_public.u.ec.publicValue.data = (guint8 *) g_bytes_get_data (claim->pk_f, NULL);
/* SDCP Connect: 5.i. Perform key agreement */ /* SDCP Connect: 5.i. Perform key agreement */
r = ECDH_Derive (&pk_f, a = PK11_PubDeriveWithKDF (priv->host_key_private,
&priv->host_key_private->ecParams, &firmware_key_public,
&priv->host_key_private->privateValue, TRUE,
FALSE, NULL,
&a_raw); NULL,
if (r != SECSuccess) CKM_ECDH1_DERIVE,
{ CKM_SP800_108_COUNTER_KDF,
error = fpi_device_error_new_msg (FP_DEVICE_ERROR_GENERAL, CKA_DERIVE,
"Key agreement failed"); 32, /* 256 bit (HMAC) secret */
goto out; CKD_NULL,
} NULL,
NULL);
a = PK11_ImportSymKey (priv->slot,
CKM_SP800_108_COUNTER_KDF,
PK11_OriginDerive,
CKA_DERIVE,
&a_raw,
NULL);
g_clear_pointer (&a_raw.data, PORT_Free);
a_raw.len = 0;
if (!a) if (!a)
{ {

View file

@ -223,13 +223,7 @@ foreach i : driver_helpers
error('nss >=3.55 is required for SDCP support (@0@ and possibly others)'.format(driver)) error('nss >=3.55 is required for SDCP support (@0@ and possibly others)'.format(driver))
endif endif
freebl_dep = cc.find_library('freebl', required: false)
if not freebl_dep.found()
error('The static freebl library from nss is required for SDCP support (@0@ and possibly others)'.format(driver))
endif
optional_deps += nss_dep optional_deps += nss_dep
optional_deps += freebl_dep
elif i == 'udev' elif i == 'udev'
install_udev_rules = true install_udev_rules = true

View file

@ -75,6 +75,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
@ -115,6 +116,7 @@ if get_option('introspection')
suite: ut_suite, suite: ut_suite,
depends: libfprint_typelib, depends: libfprint_typelib,
env: sdcp_envs, env: sdcp_envs,
workdir: meson.current_source_dir(),
) )
endforeach endforeach
else else
@ -139,6 +141,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.