Skip to content

Commit

Permalink
refactor(device): implement verification key once
Browse files Browse the repository at this point in the history
The verification key has a fixed source, so remove the vfunc.
  • Loading branch information
andyholmes committed Dec 16, 2024
1 parent ab7f7b6 commit eb91772
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 79 deletions.
64 changes: 44 additions & 20 deletions src/libvalent/device/valent-channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <json-glib/json-glib.h>
#include <libvalent-core.h>

#include "valent-certificate.h"
#include "valent-packet.h"

#include "valent-channel.h"
Expand Down Expand Up @@ -40,9 +41,8 @@
*
* Implementations should override [[email protected]] and
* [[email protected]] to support accepting and opening auxiliary
* connections, respectively. If pairing involves exchanging a key, override
* [[email protected]_verification_key]. To know when to store persistent
* data related to the connection, override [[email protected]_data].
* connections, respectively. To know when to store persistent data related to
* the connection, override [[email protected]_data].
*
* Since: 1.0
*/
Expand All @@ -54,6 +54,7 @@ typedef struct
JsonNode *identity;
GTlsCertificate *peer_certificate;
JsonNode *peer_identity;
char *verification_key;

/* Packet Buffer */
GDataInputStream *input_buffer;
Expand All @@ -74,12 +75,6 @@ static GParamSpec *properties[PROP_PEER_IDENTITY + 1] = { NULL, };


/* LCOV_EXCL_START */
static const char *
valent_channel_real_get_verification_key (ValentChannel *channel)
{
return NULL;
}

static GIOStream *
valent_channel_real_download (ValentChannel *channel,
JsonNode *packet,
Expand Down Expand Up @@ -336,6 +331,7 @@ valent_channel_finalize (GObject *object)
g_clear_pointer (&priv->identity, json_node_unref);
g_clear_object (&priv->peer_certificate);
g_clear_pointer (&priv->peer_identity, json_node_unref);
g_clear_pointer (&priv->verification_key, g_free);
valent_object_unlock (VALENT_OBJECT (self));

G_OBJECT_CLASS (valent_channel_parent_class)->finalize (object);
Expand Down Expand Up @@ -422,7 +418,6 @@ valent_channel_class_init (ValentChannelClass *klass)
object_class->get_property = valent_channel_get_property;
object_class->set_property = valent_channel_set_property;

klass->get_verification_key = valent_channel_real_get_verification_key;
klass->download = valent_channel_real_download;
klass->download_async = valent_channel_real_download_async;
klass->download_finish = valent_channel_real_download_finish;
Expand Down Expand Up @@ -646,30 +641,59 @@ valent_channel_get_peer_identity (ValentChannel *channel)
}

/**
* valent_channel_get_verification_key: (virtual get_verification_key)
* valent_channel_get_verification_key:
* @channel: a `ValentChannel`
*
* Get a verification key for the connection.
*
* Implementations that involve exchanging a key should return a string for the
* user to authenticate the connection, similar to a Bluetooth PIN.
*
* Returns: (transfer none): a verification key
* Returns: (nullable) (transfer none): a verification key
*
* Since: 1.0
*/
const char *
valent_channel_get_verification_key (ValentChannel *channel)
{
const char *ret;

VALENT_ENTRY;
ValentChannelPrivate *priv = valent_channel_get_instance_private (channel);

g_return_val_if_fail (VALENT_IS_CHANNEL (channel), NULL);

ret = VALENT_CHANNEL_GET_CLASS (channel)->get_verification_key (channel);
if (priv->verification_key == NULL)
{
g_autoptr (GChecksum) checksum = NULL;
GTlsCertificate *cert = NULL;
GTlsCertificate *peer_cert = NULL;
GByteArray *pubkey;
GByteArray *peer_pubkey;
size_t cmplen;

cert = valent_channel_get_certificate (channel);
peer_cert = valent_channel_get_peer_certificate (channel);
if (cert == NULL || peer_cert == NULL)
return NULL;

pubkey = valent_certificate_get_public_key (cert);
peer_pubkey = valent_certificate_get_public_key (peer_cert);
if (pubkey == NULL || peer_pubkey == NULL)
return NULL;

checksum = g_checksum_new (G_CHECKSUM_SHA256);
cmplen = MIN (pubkey->len, peer_pubkey->len);

if (memcmp (pubkey->data, peer_pubkey->data, cmplen) > 0)
{
g_checksum_update (checksum, pubkey->data, pubkey->len);
g_checksum_update (checksum, peer_pubkey->data, peer_pubkey->len);
}
else
{
g_checksum_update (checksum, peer_pubkey->data, peer_pubkey->len);
g_checksum_update (checksum, pubkey->data, pubkey->len);
}

priv->verification_key = g_strndup (g_checksum_get_string (checksum), 8);
}

VALENT_RETURN (ret);
return priv->verification_key;
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/libvalent/device/valent-channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ struct _ValentChannelClass
ValentObjectClass parent_class;

/* virtual functions */
const char * (*get_verification_key) (ValentChannel *channel);
GIOStream * (*download) (ValentChannel *channel,
JsonNode *packet,
GCancellable *cancellable,
Expand Down
50 changes: 3 additions & 47 deletions src/plugins/lan/valent-lan-channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@

struct _ValentLanChannel
{
ValentChannel parent_instance;
ValentChannel parent_instance;

char *verification_key;
char *host;
uint16_t port;
char *host;
uint16_t port;
};

G_DEFINE_FINAL_TYPE (ValentLanChannel, valent_lan_channel, VALENT_TYPE_CHANNEL)
Expand All @@ -36,47 +35,6 @@ static GParamSpec *properties[PROP_PORT + 1] = { NULL, };
/*
* ValentChannel
*/
static const char *
valent_lan_channel_get_verification_key (ValentChannel *channel)
{
ValentLanChannel *self = VALENT_LAN_CHANNEL (channel);
g_autoptr (GChecksum) checksum = NULL;
GTlsCertificate *cert = NULL;
GTlsCertificate *peer_cert = NULL;
GByteArray *pubkey;
GByteArray *peer_pubkey;
size_t cmplen;

if (self->verification_key == NULL)
{
if ((cert = valent_channel_get_certificate (channel)) == NULL ||
(peer_cert = valent_channel_get_peer_certificate (channel)) == NULL)
g_return_val_if_reached (NULL);

if ((pubkey = valent_certificate_get_public_key (cert)) == NULL ||
(peer_pubkey = valent_certificate_get_public_key (peer_cert)) == NULL)
g_return_val_if_reached (NULL);

checksum = g_checksum_new (G_CHECKSUM_SHA256);
cmplen = MIN (pubkey->len, peer_pubkey->len);

if (memcmp (pubkey->data, peer_pubkey->data, cmplen) > 0)
{
g_checksum_update (checksum, pubkey->data, pubkey->len);
g_checksum_update (checksum, peer_pubkey->data, peer_pubkey->len);
}
else
{
g_checksum_update (checksum, peer_pubkey->data, peer_pubkey->len);
g_checksum_update (checksum, pubkey->data, pubkey->len);
}

self->verification_key = g_strndup (g_checksum_get_string (checksum), 8);
}

return self->verification_key;
}

static GIOStream *
valent_lan_channel_download (ValentChannel *channel,
JsonNode *packet,
Expand Down Expand Up @@ -256,7 +214,6 @@ valent_lan_channel_finalize (GObject *object)
ValentLanChannel *self = VALENT_LAN_CHANNEL (object);

g_clear_pointer (&self->host, g_free);
g_clear_pointer (&self->verification_key, g_free);

G_OBJECT_CLASS (valent_lan_channel_parent_class)->finalize (object);
}
Expand Down Expand Up @@ -321,7 +278,6 @@ valent_lan_channel_class_init (ValentLanChannelClass *klass)
object_class->get_property = valent_lan_channel_get_property;
object_class->set_property = valent_lan_channel_set_property;

channel_class->get_verification_key = valent_lan_channel_get_verification_key;
channel_class->download = valent_lan_channel_download;
channel_class->upload = valent_lan_channel_upload;
channel_class->store_data = valent_lan_channel_store_data;
Expand Down
9 changes: 0 additions & 9 deletions tests/fixtures/valent-mock-channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,6 @@ static GParamSpec *properties[N_PROPERTIES] = { NULL, };
/*
* ValentChannel
*/
static const char *
valent_mock_channel_get_verification_key (ValentChannel *channel)
{
g_assert (VALENT_IS_MOCK_CHANNEL (channel));

return "Mock Channel";
}

static GIOStream *
valent_mock_channel_download (ValentChannel *channel,
JsonNode *packet,
Expand Down Expand Up @@ -217,7 +209,6 @@ valent_mock_channel_class_init (ValentMockChannelClass *klass)
object_class->get_property = valent_mock_channel_get_property;
object_class->set_property = valent_mock_channel_set_property;

channel_class->get_verification_key = valent_mock_channel_get_verification_key;
channel_class->download = valent_mock_channel_download;
channel_class->upload = valent_mock_channel_upload;

Expand Down
4 changes: 2 additions & 2 deletions tests/libvalent/device/test-channel-service.c
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,8 @@ test_channel_service_channel (ChannelServiceFixture *fixture,

channel_verification = valent_channel_get_verification_key (fixture->channel);
endpoint_verification = valent_channel_get_verification_key (fixture->endpoint);
g_assert_nonnull (channel_verification);
g_assert_nonnull (endpoint_verification);
g_assert_null (channel_verification);
g_assert_null (endpoint_verification);
g_assert_cmpstr (channel_verification, ==, endpoint_verification);

/* Packet Exchange */
Expand Down

0 comments on commit eb91772

Please sign in to comment.