From eb91772264d7d493289cd500f0fecf3f4085d562 Mon Sep 17 00:00:00 2001 From: Andy Holmes Date: Sun, 15 Dec 2024 16:38:17 -0800 Subject: [PATCH] refactor(device): implement verification key once The verification key has a fixed source, so remove the vfunc. --- src/libvalent/device/valent-channel.c | 64 +++++++++++++------ src/libvalent/device/valent-channel.h | 1 - src/plugins/lan/valent-lan-channel.c | 50 +-------------- tests/fixtures/valent-mock-channel.c | 9 --- tests/libvalent/device/test-channel-service.c | 4 +- 5 files changed, 49 insertions(+), 79 deletions(-) diff --git a/src/libvalent/device/valent-channel.c b/src/libvalent/device/valent-channel.c index f08c2232c6..187a13ce7d 100644 --- a/src/libvalent/device/valent-channel.c +++ b/src/libvalent/device/valent-channel.c @@ -11,6 +11,7 @@ #include #include +#include "valent-certificate.h" #include "valent-packet.h" #include "valent-channel.h" @@ -40,9 +41,8 @@ * * Implementations should override [vfunc@Valent.Channel.download] and * [vfunc@Valent.Channel.upload] to support accepting and opening auxiliary - * connections, respectively. If pairing involves exchanging a key, override - * [vfunc@Valent.Channel.get_verification_key]. To know when to store persistent - * data related to the connection, override [vfunc@Valent.Channel.store_data]. + * connections, respectively. To know when to store persistent data related to + * the connection, override [vfunc@Valent.Channel.store_data]. * * Since: 1.0 */ @@ -54,6 +54,7 @@ typedef struct JsonNode *identity; GTlsCertificate *peer_certificate; JsonNode *peer_identity; + char *verification_key; /* Packet Buffer */ GDataInputStream *input_buffer; @@ -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, @@ -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); @@ -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; @@ -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; } /** diff --git a/src/libvalent/device/valent-channel.h b/src/libvalent/device/valent-channel.h index 5f645401bb..5bb910f1b9 100644 --- a/src/libvalent/device/valent-channel.h +++ b/src/libvalent/device/valent-channel.h @@ -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, diff --git a/src/plugins/lan/valent-lan-channel.c b/src/plugins/lan/valent-lan-channel.c index ba51a1beec..46f6579731 100644 --- a/src/plugins/lan/valent-lan-channel.c +++ b/src/plugins/lan/valent-lan-channel.c @@ -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) @@ -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, @@ -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); } @@ -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; diff --git a/tests/fixtures/valent-mock-channel.c b/tests/fixtures/valent-mock-channel.c index dbc73c293e..df533d38e9 100644 --- a/tests/fixtures/valent-mock-channel.c +++ b/tests/fixtures/valent-mock-channel.c @@ -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, @@ -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; diff --git a/tests/libvalent/device/test-channel-service.c b/tests/libvalent/device/test-channel-service.c index 9d40286be9..fb164a7b44 100644 --- a/tests/libvalent/device/test-channel-service.c +++ b/tests/libvalent/device/test-channel-service.c @@ -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 */