Commit 8db2b978 authored by Stef Walter's avatar Stef Walter Committed by Daiki Ueno

ssh-agent: Use stock ssh-agent

This patch removes our own implementation of ssh-agent and switches to
using the ssh-agent program provided by OpenSSH.  We can't simply drop
the ssh-agent functionality from gnome-keyring, as it enables the
following:

 * Automatic loading and unlocking of keys
 * Prompting in the UI

Instead we wrap the ssh-agent program as a subprocess and augment
the protocol as we need.
Co-authored-by: Daiki Ueno's avatarDaiki Ueno <dueno@src.gnome.org>

https://bugzilla.gnome.org/show_bug.cgi?id=775981
parent 43f9d81d
......@@ -347,14 +347,23 @@ AC_ARG_ENABLE([ssh-agent],
AC_HELP_STRING([--disable-ssh-agent],
[Don't include SSH agent in gnome-keyring]))
AC_PATH_PROG([SSH_AGENT], [ssh-agent], [false])
AC_DEFINE_UNQUOTED(SSH_AGENT, "$SSH_AGENT", [The path to ssh-agent])
AC_PATH_PROG([SSH_ADD], [ssh-add], [false])
AC_DEFINE_UNQUOTED(SSH_ADD, "$SSH_ADD", [The path to ssh-add])
if test "$enable_ssh_agent" != "no"; then
AC_DEFINE(WITH_SSH, 1, [Whether to build SSH agent or not])
ssh_status="yes"
else
ssh_status="no"
if test "$SSH_AGENT" = "false" -o "$SSH_ADD" = "false"; then
enable_ssh_agent=no
else
enable_ssh_agent=yes
AC_DEFINE(WITH_SSH, 1, [Whether to build SSH agent or not])
fi
fi
AM_CONDITIONAL(WITH_SSH, test "$enable_ssh_agent" != "no")
ssh_status="$enable_ssh_agent"
# --------------------------------------------------------------------
# libgcrypt
......
......@@ -16,9 +16,9 @@ gnome_keyring_daemon_SOURCES = \
$(NULL)
gnome_keyring_daemon_LDADD = \
libgkd-dbus.la \
libgkd-login.la \
libgkd-control.la \
libgkd-ssh-agent.la \
libgkd-login.la \
libgkm-wrap-layer.la \
libgkm-rpc-layer.la \
libgkm-secret-store.la \
......
......@@ -23,46 +23,44 @@
#include "gkd-glue.h"
#include "gkd-util.h"
#include "ssh-agent/gkd-ssh-agent.h"
#include "ssh-agent/gkd-ssh-agent-service.h"
#include "ssh-agent/gkd-ssh-agent-interaction.h"
#include "egg/egg-cleanup.h"
static void
pkcs11_ssh_cleanup (gpointer unused)
pkcs11_ssh_cleanup (gpointer data)
{
gkd_ssh_agent_shutdown ();
}
static gboolean
accept_ssh_client (GIOChannel *channel, GIOCondition cond, gpointer unused)
{
if (cond == G_IO_IN)
gkd_ssh_agent_accept ();
return TRUE;
GkdSshAgentService *service = GKD_SSH_AGENT_SERVICE (data);
gkd_ssh_agent_service_stop (service);
g_object_unref (service);
}
gboolean
gkd_daemon_startup_ssh (void)
{
GIOChannel *channel;
const gchar *base_dir;
int sock;
GTlsInteraction *interaction;
GkdSshAgentPreload *preload;
GkdSshAgentService *service;
base_dir = gkd_util_get_master_directory ();
g_return_val_if_fail (base_dir, FALSE);
sock = gkd_ssh_agent_startup (base_dir);
if (sock == -1)
return FALSE;
interaction = gkd_ssh_agent_interaction_new (NULL);
preload = gkd_ssh_agent_preload_new ("~/.ssh");
service = gkd_ssh_agent_service_new (base_dir, interaction, preload);
g_object_unref (interaction);
g_object_unref (preload);
channel = g_io_channel_unix_new (sock);
g_io_add_watch (channel, G_IO_IN | G_IO_HUP, accept_ssh_client, NULL);
g_io_channel_unref (channel);
if (!gkd_ssh_agent_service_start (service))
return FALSE;
/* ssh-agent sets the environment variable */
gkd_util_push_environment ("SSH_AUTH_SOCK", g_getenv ("SSH_AUTH_SOCK"));
egg_cleanup_register (pkcs11_ssh_cleanup, NULL);
egg_cleanup_register (pkcs11_ssh_cleanup, service);
return TRUE;
}
......@@ -32,7 +32,7 @@
#include "pkcs11/gnome2-store/gkm-gnome2-store.h"
#include "pkcs11/xdg-store/gkm-xdg-store.h"
#include "ssh-agent/gkd-ssh-agent.h"
#include "ssh-agent/gkd-ssh-agent-service.h"
#include <string.h>
......@@ -49,7 +49,6 @@ pkcs11_daemon_cleanup (gpointer unused)
g_assert (pkcs11_roof);
gkd_ssh_agent_uninitialize ();
gkm_rpc_layer_uninitialize ();
rv = (pkcs11_roof->C_Finalize) (NULL);
......@@ -67,7 +66,6 @@ gkd_pkcs11_initialize (void)
CK_FUNCTION_LIST_PTR gnome2_store;
CK_FUNCTION_LIST_PTR xdg_store;
CK_C_INITIALIZE_ARGS init_args;
gboolean ret;
CK_RV rv;
/* Secrets */
......@@ -113,10 +111,7 @@ gkd_pkcs11_initialize (void)
egg_cleanup_register (pkcs11_daemon_cleanup, NULL);
ret = gkd_ssh_agent_initialize (pkcs11_roof) &&
gkm_rpc_layer_initialize (pkcs11_roof);
return ret;
return gkm_rpc_layer_initialize (pkcs11_roof);
}
static void
......@@ -157,46 +152,6 @@ gkd_pkcs11_startup_pkcs11 (void)
return TRUE;
}
static void
pkcs11_ssh_cleanup (gpointer unused)
{
gkd_ssh_agent_shutdown ();
}
static gboolean
accept_ssh_client (GIOChannel *channel, GIOCondition cond, gpointer unused)
{
if (cond == G_IO_IN)
gkd_ssh_agent_accept ();
return TRUE;
}
gboolean
gkd_pkcs11_startup_ssh (void)
{
GIOChannel *channel;
const gchar *base_dir;
int sock;
base_dir = gkd_util_get_master_directory ();
g_return_val_if_fail (base_dir, FALSE);
sock = gkd_ssh_agent_startup (base_dir);
if (sock == -1)
return FALSE;
channel = g_io_channel_unix_new (sock);
g_io_add_watch (channel, G_IO_IN | G_IO_HUP, accept_ssh_client, NULL);
g_io_channel_unref (channel);
/* gkm-ssh-agent sets the environment variable */
gkd_util_push_environment ("SSH_AUTH_SOCK", g_getenv ("SSH_AUTH_SOCK"));
egg_cleanup_register (pkcs11_ssh_cleanup, NULL);
return TRUE;
}
CK_FUNCTION_LIST_PTR
gkd_pkcs11_get_functions (void)
{
......
......@@ -29,8 +29,6 @@ gboolean gkd_pkcs11_initialize (void);
gboolean gkd_pkcs11_startup_pkcs11 (void);
gboolean gkd_pkcs11_startup_ssh (void);
CK_FUNCTION_LIST_PTR gkd_pkcs11_get_functions (void);
CK_FUNCTION_LIST_PTR gkd_pkcs11_get_base_functions (void);
......
......@@ -6,63 +6,75 @@ noinst_LTLIBRARIES += \
libgkd-ssh-agent.la
libgkd_ssh_agent_la_SOURCES = \
daemon/ssh-agent/gkd-ssh-agent.c \
daemon/ssh-agent/gkd-ssh-agent.h \
daemon/ssh-agent/gkd-ssh-agent-interaction.c \
daemon/ssh-agent/gkd-ssh-agent-interaction.h \
daemon/ssh-agent/gkd-ssh-agent-process.h \
daemon/ssh-agent/gkd-ssh-agent-process.c \
daemon/ssh-agent/gkd-ssh-agent-preload.h \
daemon/ssh-agent/gkd-ssh-agent-preload.c \
daemon/ssh-agent/gkd-ssh-agent-private.h \
daemon/ssh-agent/gkd-ssh-agent-ops.c \
daemon/ssh-agent/gkd-ssh-agent-proto.c
daemon/ssh-agent/gkd-ssh-agent-service.c \
daemon/ssh-agent/gkd-ssh-agent-service.h \
daemon/ssh-agent/gkd-ssh-agent-util.c \
daemon/ssh-agent/gkd-ssh-agent-util.h \
$(NULL)
libgkd_ssh_agent_la_CFLAGS = \
$(DAEMON_CFLAGS)
# ------------------------------------------------------------------------------
# Standalone binary
# Tests
noinst_LTLIBRARIES += \
libgkd-ssh-agent-test.la
noinst_PROGRAMS += \
gkd-ssh-agent-standalone
libgkd_ssh_agent_test_la_SOURCES = \
daemon/ssh-agent/test-common.c \
daemon/ssh-agent/test-common.h
gkd_ssh_agent_standalone_SOURCES = \
daemon/ssh-agent/gkd-ssh-agent-standalone.c
gkd_ssh_agent_standalone_CFLAGS = \
libgkd_ssh_agent_test_la_CFLAGS = \
$(DAEMON_CFLAGS)
gkd_ssh_agent_standalone_LDADD = \
libgkd-ssh-agent.la \
libgkd_ssh_agent_test_la_LIBADD = \
libegg-buffer.la \
libegg-secure.la \
libgkm.la \
libgkm-wrap-layer.la \
$(DAEMON_LIBS)
# ------------------------------------------------------------------------------
# Tests
ssh_agent_CFLAGS = \
$(GCK_CFLAGS)
$(DAEMON_CFLAGS)
ssh_agent_LIBS = \
libgkd-ssh-agent.la \
libgkm.la \
libgkd-ssh-agent-test.la \
libegg.la \
$(GLIB_LIBS) \
$(GCK_LIBS)
$(GTHREAD_LIBS)
$(DAEMON_LIBS)
ssh_agent_TESTS = \
test-communication \
test-keytypes \
test-gkd-ssh-agent-interaction
test-gkd-ssh-agent-interaction \
test-gkd-ssh-agent-preload \
test-gkd-ssh-agent-process \
test-gkd-ssh-agent-service \
test-gkd-ssh-agent-util
test_gkd_ssh_agent_preload_SOURCES = daemon/ssh-agent/test-gkd-ssh-agent-preload.c
test_gkd_ssh_agent_preload_CFLAGS = $(ssh_agent_CFLAGS)
test_gkd_ssh_agent_preload_LDADD = $(ssh_agent_LIBS)
test_gkd_ssh_agent_process_SOURCES = daemon/ssh-agent/test-gkd-ssh-agent-process.c
test_gkd_ssh_agent_process_CFLAGS = $(ssh_agent_CFLAGS)
test_gkd_ssh_agent_process_LDADD = $(ssh_agent_LIBS)
test_keytypes_SOURCES = daemon/ssh-agent/test-keytypes.c
test_keytypes_CFLAGS = $(ssh_agent_CFLAGS)
test_keytypes_LDADD = $(ssh_agent_LIBS)
test_gkd_ssh_agent_service_SOURCES = daemon/ssh-agent/test-gkd-ssh-agent-service.c
test_gkd_ssh_agent_service_CFLAGS = $(ssh_agent_CFLAGS)
test_gkd_ssh_agent_service_LDADD = $(ssh_agent_LIBS) libgkd-login.la libgkm-wrap-layer.la
test_communication_SOURCES = daemon/ssh-agent/test-communication.c
test_communication_CFLAGS = $(ssh_agent_CFLAGS)
test_communication_LDADD = $(ssh_agent_LIBS)
test_gkd_ssh_agent_util_SOURCES = daemon/ssh-agent/test-gkd-ssh-agent-util.c
test_gkd_ssh_agent_util_CFLAGS = $(ssh_agent_CFLAGS)
test_gkd_ssh_agent_util_LDADD = $(ssh_agent_LIBS)
test_gkd_ssh_agent_interaction_SOURCES = daemon/ssh-agent/test-gkd-ssh-agent-interaction.c
test_gkd_ssh_agent_interaction_CFLAGS = $(ssh_agent_CFLAGS)
test_gkd_ssh_agent_interaction_LDADD = $(ssh_agent_LIBS) libgkd-login.la libgkm-wrap-layer.la
test_gkd_ssh_agent_interaction_LDADD = $(ssh_agent_LIBS) libgkd-login.la
if WITH_SSH
check_PROGRAMS += $(ssh_agent_TESTS)
TESTS += $(ssh_agent_TESTS)
endif
This diff is collapsed.
/*
* gnome-keyring
*
* Copyright (C) 2014 Stef Walter
* Copyright (C) 2018 Red Hat, Inc.
*
* This program 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 program 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 program; if not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Stef Walter <stef@thewalter.net>, Daiki Ueno
*/
#include "config.h"
#include "gkd-ssh-agent-preload.h"
#include "gkd-ssh-agent-util.h"
#include "egg/egg-file-tracker.h"
#include <string.h>
enum {
PROP_0,
PROP_PATH
};
struct _GkdSshAgentPreload
{
GObject object;
gchar *path;
GHashTable *keys_by_public_filename;
GHashTable *keys_by_public_key;
EggFileTracker *file_tracker;
GMutex lock;
};
G_DEFINE_TYPE (GkdSshAgentPreload, gkd_ssh_agent_preload, G_TYPE_OBJECT);
void
gkd_ssh_agent_key_info_free (gpointer boxed)
{
GkdSshAgentKeyInfo *info = boxed;
if (!info)
return;
g_bytes_unref (info->public_key);
g_free (info->comment);
g_free (info->filename);
g_free (info);
}
gpointer
gkd_ssh_agent_key_info_copy (gpointer boxed)
{
GkdSshAgentKeyInfo *info = boxed;
GkdSshAgentKeyInfo *copy = g_new0 (GkdSshAgentKeyInfo, 1);
copy->public_key = g_bytes_ref (info->public_key);
copy->comment = g_strdup (info->comment);
copy->filename = g_strdup (info->filename);
return copy;
}
static void file_load_inlock (EggFileTracker *tracker,
const gchar *path,
gpointer user_data);
static void file_remove_inlock (EggFileTracker *tracker,
const gchar *path,
gpointer user_data);
static void
gkd_ssh_agent_preload_init (GkdSshAgentPreload *self)
{
self->keys_by_public_filename = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
self->keys_by_public_key = g_hash_table_new_full (g_bytes_hash, g_bytes_equal, NULL, gkd_ssh_agent_key_info_free);
}
static void
gkd_ssh_agent_preload_constructed (GObject *object)
{
GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (object);
self->file_tracker = egg_file_tracker_new (self->path, "*.pub", NULL);
g_signal_connect (self->file_tracker, "file-added", G_CALLBACK (file_load_inlock), self);
g_signal_connect (self->file_tracker, "file-removed", G_CALLBACK (file_remove_inlock), self);
g_signal_connect (self->file_tracker, "file-changed", G_CALLBACK (file_load_inlock), self);
G_OBJECT_CLASS (gkd_ssh_agent_preload_parent_class)->constructed (object);
}
static void
gkd_ssh_agent_preload_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (object);
switch (prop_id) {
case PROP_PATH:
self->path = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gkd_ssh_agent_preload_finalize (GObject *object)
{
GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (object);
g_free (self->path);
g_clear_pointer (&self->keys_by_public_key, (GDestroyNotify) g_hash_table_unref);
g_clear_pointer (&self->keys_by_public_filename, (GDestroyNotify) g_hash_table_unref);
g_clear_object (&self->file_tracker);
g_mutex_clear (&self->lock);
G_OBJECT_CLASS (gkd_ssh_agent_preload_parent_class)->finalize (object);
}
static void
gkd_ssh_agent_preload_class_init (GkdSshAgentPreloadClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->constructed = gkd_ssh_agent_preload_constructed;
gobject_class->set_property = gkd_ssh_agent_preload_set_property;
gobject_class->finalize = gkd_ssh_agent_preload_finalize;
g_object_class_install_property (gobject_class, PROP_PATH,
g_param_spec_string ("path", "Path", "Path",
"",
G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE));
}
static gchar *
private_path_for_public (const gchar *public_path)
{
if (g_str_has_suffix (public_path, ".pub"))
return g_strndup (public_path, strlen (public_path) - 4);
return NULL;
}
static GBytes *
file_get_contents (const gchar *path,
gboolean must_be_present)
{
GError *error = NULL;
gchar *contents;
gsize length;
if (!g_file_get_contents (path, &contents, &length, &error)) {
if (must_be_present || error->code != G_FILE_ERROR_NOENT)
g_message ("couldn't read file: %s: %s", path, error->message);
g_error_free (error);
return NULL;
}
return g_bytes_new_take (contents, length);
}
static void
file_remove_inlock (EggFileTracker *tracker,
const gchar *path,
gpointer user_data)
{
GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (user_data);
GkdSshAgentKeyInfo *info;
info = g_hash_table_lookup (self->keys_by_public_filename, path);
if (info) {
g_hash_table_remove (self->keys_by_public_filename, path);
g_hash_table_remove (self->keys_by_public_key, info->public_key);
}
}
static void
file_load_inlock (EggFileTracker *tracker,
const gchar *path,
gpointer user_data)
{
GkdSshAgentPreload *self = GKD_SSH_AGENT_PRELOAD (user_data);
gchar *private_path;
GBytes *private_bytes;
GBytes *public_bytes;
GBytes *public_key;
GkdSshAgentKeyInfo *info;
gchar *comment;
file_remove_inlock (tracker, path, user_data);
private_path = private_path_for_public (path);
private_bytes = file_get_contents (private_path, FALSE);
if (!private_bytes) {
g_debug ("no private key present for public key: %s", path);
g_free (private_path);
return;
}
public_bytes = file_get_contents (path, TRUE);
if (public_bytes) {
public_key = _gkd_ssh_agent_parse_public_key (public_bytes, &comment);
if (public_key) {
info = g_new0 (GkdSshAgentKeyInfo, 1);
info->filename = private_path;
private_path = NULL;
info->public_key = public_key;
info->comment = comment;
g_hash_table_replace (self->keys_by_public_filename, g_strdup (path), info);
g_hash_table_replace (self->keys_by_public_key, info->public_key, info);
} else {
g_message ("failed to parse ssh public key: %s", path);
}
g_bytes_unref (public_bytes);
}
g_bytes_unref (private_bytes);
g_free (private_path);
}
GkdSshAgentPreload *
gkd_ssh_agent_preload_new (const gchar *path)
{
g_return_val_if_fail (path, NULL);
return g_object_new (GKD_TYPE_SSH_AGENT_PRELOAD, "path", path, NULL);
}
GList *
gkd_ssh_agent_preload_get_keys (GkdSshAgentPreload *self)
{
GList *keys = NULL;
GHashTableIter iter;
GkdSshAgentKeyInfo *info;
g_mutex_lock (&self->lock);
egg_file_tracker_refresh (self->file_tracker, FALSE);
g_hash_table_iter_init (&iter, self->keys_by_public_key);
while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&info))
keys = g_list_prepend (keys, gkd_ssh_agent_key_info_copy (info));
g_mutex_unlock (&self->lock);
return keys;
}
GkdSshAgentKeyInfo *
gkd_ssh_agent_preload_lookup_by_public_key (GkdSshAgentPreload *self,
GBytes *public_key)
{
GkdSshAgentKeyInfo *info;
g_mutex_lock (&self->lock);
egg_file_tracker_refresh (self->file_tracker, FALSE);
info = g_hash_table_lookup (self->keys_by_public_key, public_key);
if (info)
info = gkd_ssh_agent_key_info_copy (info);
g_mutex_unlock (&self->lock);
return info;
}
/*
* gnome-keyring
*
* Copyright (C) 2014 Stef Walter
* Copyright (C) 2018 Red Hat, Inc.
*
* This program 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 program 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 program; if not, see
* <http://www.gnu.org/licenses/>.
*
* Author: Stef Walter <stef@thewalter.net>, Daiki Ueno
*/
#ifndef __GKD_SSH_AGENT_PRELOAD_H__
#define __GKD_SSH_AGENT_PRELOAD_H__
#include <glib-object.h>
typedef struct {
gchar *filename;
GBytes *public_key;
gchar *comment;
} GkdSshAgentKeyInfo;
void gkd_ssh_agent_key_info_free (gpointer boxed);
gpointer gkd_ssh_agent_key_info_copy (gpointer boxed);
#define GKD_TYPE_SSH_AGENT_PRELOAD gkd_ssh_agent_preload_get_type ()
G_DECLARE_FINAL_TYPE (GkdSshAgentPreload, gkd_ssh_agent_preload, GKD, SSH_AGENT_PRELOAD, GObject)
GkdSshAgentPreload *gkd_ssh_agent_preload_new (const gchar *path);
GList *gkd_ssh_agent_preload_get_keys (GkdSshAgentPreload *self);
GkdSshAgentKeyInfo *gkd_ssh_agent_preload_lookup_by_public_key
(GkdSshAgentPreload *self,
GBytes *public_key);
#endif /* __GKD_SSH_AGENT_PRELOAD_H__ */
......@@ -23,21 +23,6 @@
#ifndef GKDSSHPRIVATE_H_
#define GKDSSHPRIVATE_H_
#include "egg/egg-buffer.h"
#include "pkcs11/pkcs11.h"
#include <gck/gck.h>
#include <glib.h>
typedef struct _GkdSshAgentCall {
int sock;
GList *modules;
EggBuffer *req;
EggBuffer *resp;
} GkdSshAgentCall;
/* -----------------------------------------------------------------------------
* SSH OPERATIONS and CONSTANTS
*/
......@@ -82,141 +67,4 @@ typedef struct _GkdSshAgentCall {
#define GKD_SSH_FLAG_RSA_SHA2_256 0x02
#define GKD_SSH_FLAG_RSA_SHA2_512 0x04
/* -----------------------------------------------------------------------------
* gkd-ssh-agent-ops.c
*/
typedef gboolean (*GkdSshAgentOperation) (GkdSshAgentCall *call);
extern const GkdSshAgentOperation gkd_ssh_agent_operations[GKD_SSH_OP_MAX];
/* -----------------------------------------------------------------------------
* gkd-ssh-agent.c
*/
gboolean gkd_ssh_agent_initialize_with_module (GckModule *module);
GckSession* gkd_ssh_agent_checkout_main_session (void);
void gkd_ssh_agent_checkin_main_session (GckSession* session);
/* -----------------------------------------------------------------------------
* gkd-ssh-agent-proto.c
*/
gulong gkd_ssh_agent_proto_keytype_to_algo (const gchar *salgo);
const gchar* gkd_ssh_agent_proto_rsa_algo_to_keytype (GChecksumType halgo);
const gchar* gkd_ssh_agent_proto_dsa_algo_to_keytype (void);
const gchar* gkd_ssh_agent_proto_ecc_algo_to_keytype (GQuark oid);
GQuark gkd_ssh_agent_proto_curve_to_oid (const gchar *salgo);
const gchar* gkd_ssh_agent_proto_oid_to_curve (GQuark oid);
gint gkd_ssh_agent_proto_curve_oid_to_hash_algo (GQuark oid);
GQuark gkd_ssh_agent_proto_find_curve_oid (GckAttributes *attrs);
gboolean gkd_ssh_agent_proto_read_mpi (EggBuffer *req,
gsize *offset,
GckBuilder *attrs,
CK_ATTRIBUTE_TYPE type);
gboolean gkd_ssh_agent_proto_read_mpi_v1 (EggBuffer *req,
gsize *offset,
GckBuilder *attrs,
CK_ATTRIBUTE_TYPE type);
const guchar* gkd_ssh_agent_proto_read_challenge_v1 (EggBuffer *req,
gsize *offset,
gsize *n_challenge);
gboolean gkd_ssh_agent_proto_read_string_to_der (EggBuffer *req,
gsize *offset,
GckBuilder *attrs,
CK_ATTRIBUTE_TYPE type);
gboolean gkd_ssh_agent_proto_read_ecdsa_curve (EggBuffer *req,
gsize *offset,
GckBuilder *attrs);
gboolean gkd_ssh_agent_proto_write_mpi (EggBuffer *resp,
const GckAttribute *attr);
gboolean gkd_ssh_agent_proto_write_mpi_v1 (EggBuffer *resp,
const GckAttribute *attr);
gboolean gkd_ssh_agent_proto_write_string (EggBuffer *resp,
const GckAttribute *attr);
gboolean gkd_ssh_agent_proto_read_public (EggBuffer