/*
This file is part of GNUnet
Copyright (C) 2020 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License,
or (at your option) any later version.
GNUnet 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
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file escrow/plugin_escrow_gns.c
* @brief escrow-plugin-gns escrow plugin for the escrow of the key
* using GNS and escrow identities
*
* @author Johannes Späth
*/
#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_escrow_plugin.h"
#include "escrow_plugin_helper.h"
#include "gnunet_namestore_service.h"
#include "gnunet_gns_service.h"
#include "gnunet_gnsrecord_lib.h"
#include "../identity/identity.h"
#include
#include
/**
* Continuation with a private key (used for restore_private_key)
*/
typedef void (*PkContinuation) (void *cls,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk);
struct IdentityOperationEntry
{
/**
* DLL
*/
struct IdentityOperationEntry *prev;
/**
* DLL
*/
struct IdentityOperationEntry *next;
/**
* Identity operation
*/
struct GNUNET_IDENTITY_Operation *id_op;
/**
* Private key of the respective ego
*/
struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
/**
* Name of the respective ego
*/
char *name;
/**
* Index of the respective share
*/
uint8_t i;
/**
* The plugin operation that started the identity operation
*/
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
};
struct PkEntry
{
/**
* DLL
*/
struct PkEntry *prev;
/**
* DLL
*/
struct PkEntry *next;
/**
* private key
*/
struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
/**
* index of the respective share
*/
uint8_t i;
};
struct NamestoreQueueEntry
{
/**
* DLL
*/
struct NamestoreQueueEntry *prev;
/**
* DLL
*/
struct NamestoreQueueEntry *next;
/**
* Namestore queue entry
*/
struct GNUNET_NAMESTORE_QueueEntry *ns_qe;
/**
* Plugin operation that called the namestore operation
*/
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
};
// define TimeoutTaskEntry here, as it is already needed in GnsLookupRequest
struct TimeoutTaskEntry;
struct GnsLookupRequestEntry
{
/**
* DLL
*/
struct GnsLookupRequestEntry *prev;
/**
* DLL
*/
struct GnsLookupRequestEntry *next;
/**
* GNS lookup request
*/
struct GNUNET_GNS_LookupRequest *lr;
/**
* Plugin operation that started the lookup
*/
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
/**
* index of the respective share
*/
uint8_t i;
/**
* Timeout task scheduled for this lookup request
*/
struct TimeoutTaskEntry *tt;
};
struct TimeoutTaskEntry
{
/**
* DLL
*/
struct TimeoutTaskEntry *prev;
/**
* DLL
*/
struct TimeoutTaskEntry *next;
/**
* Timeout task
*/
struct GNUNET_SCHEDULER_Task *tt;
/**
* GNS lookup request this timeout is for
*/
struct GnsLookupRequestEntry *gns_lr;
/**
* Plugin operation that started the timeout
*/
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
};
struct ESCROW_GnsPluginOperation
{
/**
* Handle for the escrow component
*/
struct GNUNET_ESCROW_Handle *h;
/**
* Scheduler task the SCHEDULE operation returns (needed for cancellation)
*/
struct GNUNET_SCHEDULER_Task *sched_task;
/**
* Namestore handle
*/
struct GNUNET_NAMESTORE_Handle *ns_h;
/**
* GNS handle
*/
struct GNUNET_GNS_Handle *gns_h;
/**
* Continuation for a plugin operation (e.g. used for restore, as this
* callback has to be called from the IDENTITY service after finishing)
*/
ESCROW_Plugin_Continuation cont;
/**
* Ego continuation wrapper
*/
struct ESCROW_Plugin_EgoContinuationWrapper *ego_wrap;
/**
* Anchor continuation wrapper
*/
struct ESCROW_Plugin_AnchorContinuationWrapper *anchor_wrap;
/**
* Verify continuation wrapper
*/
struct ESCROW_Plugin_VerifyContinuationWrapper *verify_wrap;
/**
* Counter for the created escrow identities
*/
uint8_t escrow_id_counter;
/**
* Number of shares
*/
uint8_t shares;
/**
* Share threshold
*/
uint8_t share_threshold;
/**
* Continuation to be called with the restored private key
*/
PkContinuation restore_pk_cont;
/**
* Closure for @a cont
*/
void *restore_pk_cont_cls;
/**
* Array for the restored keyshares
*/
sss_Keyshare *restored_keyshares;
/**
* Identity operation for the create of the restored ego
*/
struct GNUNET_IDENTITY_Operation *id_op;
/**
* The ego
*/
struct GNUNET_IDENTITY_Ego *ego;
/**
* The name of the ego
*/
char *egoName;
/**
* Private key of the ego
*/
struct GNUNET_CRYPTO_EcdsaPrivateKey pk;
/**
* User secret string
*/
char *userSecret;
/**
* DLL head for identity operations
*/
struct IdentityOperationEntry *id_ops_head;
/**
* DLL tail for identity operations
*/
struct IdentityOperationEntry *id_ops_tail;
/**
* DLL head for escrow private keys
*/
struct PkEntry *escrow_pks_head;
/**
* DLL tail for escrow private keys
*/
struct PkEntry *escrow_pks_tail;
/**
* DLL head for namestore queue entries
*/
struct NamestoreQueueEntry *ns_qes_head;
/**
* DLL tail for namestore queue entries
*/
struct NamestoreQueueEntry *ns_qes_tail;
/**
* DLL head for GNS lookup requests
*/
struct GnsLookupRequestEntry *gns_lrs_head;
/**
* DLL tail for GNS lookup requests
*/
struct GnsLookupRequestEntry *gns_lrs_tail;
/**
* DLL head for GNS timeout tasks
*/
struct TimeoutTaskEntry *tts_head;
/**
* DLL tail for GNS timeout tasks
*/
struct TimeoutTaskEntry *tts_tail;
};
/**
* Identity handle
*/
static struct GNUNET_IDENTITY_Handle *identity_handle;
/**
* Handle for the plugin instance
*/
struct ESCROW_PluginHandle ph;
/**
* Clean up a plugin operation, i.e. remove it from the list and
* free the respective memory
*/
void
cleanup_plugin_operation (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
{
struct ESCROW_GnsPluginOperation *p_op;
struct IdentityOperationEntry *curr_id_op, *next_id_op;
struct PkEntry *curr_pk, *next_pk;
struct NamestoreQueueEntry *curr_ns_qe, *next_ns_qe;
struct GnsLookupRequestEntry *curr_gns_lr, *next_gns_lr;
struct TimeoutTaskEntry *curr_tt, *next_tt;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
GNUNET_CONTAINER_DLL_remove (ph.plugin_op_head,
ph.plugin_op_tail,
plugin_op_wrap);
if (NULL != p_op->anchor_wrap)
GNUNET_free (p_op->anchor_wrap);
if (NULL != p_op->ego_wrap)
GNUNET_free (p_op->ego_wrap);
if (NULL != p_op->verify_wrap)
GNUNET_free (p_op->verify_wrap);
if (NULL != p_op->userSecret)
GNUNET_free (p_op->userSecret);
/* clean up identity operation list */
for (curr_id_op = p_op->id_ops_head; NULL != curr_id_op; curr_id_op = next_id_op)
{
next_id_op = curr_id_op->next;
GNUNET_CONTAINER_DLL_remove (p_op->id_ops_head,
p_op->id_ops_tail,
curr_id_op);
GNUNET_IDENTITY_cancel (curr_id_op->id_op);
GNUNET_free (curr_id_op->pk);
GNUNET_free (curr_id_op->name);
GNUNET_free (curr_id_op);
}
/* clean up escrow pk list */
for (curr_pk = p_op->escrow_pks_head; NULL != curr_pk; curr_pk = next_pk)
{
next_pk = curr_pk->next;
GNUNET_CONTAINER_DLL_remove (p_op->escrow_pks_head,
p_op->escrow_pks_tail,
curr_pk);
GNUNET_free (curr_pk);
}
/* clean up namestore operation list */
for (curr_ns_qe = p_op->ns_qes_head; NULL != curr_ns_qe; curr_ns_qe = next_ns_qe)
{
next_ns_qe = curr_ns_qe->next;
GNUNET_CONTAINER_DLL_remove (p_op->ns_qes_head,
p_op->ns_qes_tail,
curr_ns_qe);
// also frees the curr_ns_qe->ns_qe
GNUNET_NAMESTORE_cancel (curr_ns_qe->ns_qe);
GNUNET_free (curr_ns_qe);
}
/* clean up GNS lookup request list */
for (curr_gns_lr = p_op->gns_lrs_head; NULL != curr_gns_lr; curr_gns_lr = next_gns_lr)
{
next_gns_lr = curr_gns_lr->next;
GNUNET_CONTAINER_DLL_remove (p_op->gns_lrs_head,
p_op->gns_lrs_tail,
curr_gns_lr);
GNUNET_GNS_lookup_cancel (curr_gns_lr->lr);
GNUNET_free (curr_gns_lr);
}
/* clean up timeout task list */
for (curr_tt = p_op->tts_head; NULL != curr_tt; curr_tt = next_tt)
{
next_tt = curr_tt->next;
GNUNET_CONTAINER_DLL_remove (p_op->tts_head,
p_op->tts_tail,
curr_tt);
GNUNET_SCHEDULER_cancel (curr_tt->tt);
GNUNET_free (curr_tt);
}
/* free the keyshares array */
if (NULL != p_op->restored_keyshares)
GNUNET_free (p_op->restored_keyshares);
/* disconnect from namestore service */
if (NULL != p_op->ns_h)
GNUNET_NAMESTORE_disconnect (p_op->ns_h);
/* disconnect from GNS service */
if (NULL != p_op->gns_h)
GNUNET_GNS_disconnect (p_op->gns_h);
/* cancel scheduled task */
if (NULL != p_op->sched_task)
GNUNET_SCHEDULER_cancel (p_op->sched_task);
/* cancel identity operation */
if (NULL != p_op->id_op)
GNUNET_IDENTITY_cancel (p_op->id_op);
if (NULL != p_op->egoName)
GNUNET_free (p_op->egoName);
GNUNET_free (p_op);
GNUNET_free (plugin_op_wrap);
}
void
start_cont (void *cls)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
p_op->cont (p_op->anchor_wrap);
cleanup_plugin_operation (plugin_op_wrap);
}
void
verify_cont (void *cls)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
p_op->cont (p_op->verify_wrap);
cleanup_plugin_operation (plugin_op_wrap);
}
static void
handle_restore_error (void *cls)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
p_op->cont (p_op->ego_wrap);
cleanup_plugin_operation (plugin_op_wrap);
}
sss_Keyshare *
split_private_key (struct ESCROW_GnsPluginOperation *p_op)
{
sss_Keyshare *keyshares;
keyshares = GNUNET_malloc (sizeof (sss_Keyshare) * p_op->shares);
sss_create_keyshares (keyshares,
p_op->pk.d,
p_op->shares,
p_op->share_threshold);
return keyshares;
}
static void
keyshare_distribution_finished (void *cls)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
struct GNUNET_ESCROW_Anchor *anchor;
int anchorDataSize;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All keyshares distributed\n");
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
anchorDataSize = strlen(p_op->userSecret) + 1;
anchor = GNUNET_malloc (sizeof (struct GNUNET_ESCROW_Anchor) + anchorDataSize);
anchor->method = GNUNET_ESCROW_KEY_GNS;
anchor->egoName = GNUNET_strdup (p_op->ego->name);
anchor->size = anchorDataSize;
GNUNET_memcpy (&anchor[1], p_op->userSecret, anchorDataSize);
p_op->anchor_wrap->anchor = anchor;
/* set the last escrow time */
ESCROW_update_escrow_status (p_op->h, p_op->ego, "gns");
/* call the continuation */
start_cont (plugin_op_wrap);
}
static void
keyshare_distributed (void *cls,
int32_t success,
const char *emsg)
{
struct NamestoreQueueEntry *ns_qe = cls;
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
struct ESCROW_GnsPluginOperation *p_op;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Keyshare distributed\n");
plugin_op_wrap = ns_qe->plugin_op_wrap;
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
// remove qe from our list
GNUNET_CONTAINER_DLL_remove (p_op->ns_qes_head,
p_op->ns_qes_tail,
ns_qe);
if (GNUNET_SYSERR == success)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to store keyshare %s\n",
emsg);
p_op->anchor_wrap->anchor = NULL;
p_op->anchor_wrap->emsg = _ ("Keyshare distribution failed!\n");
p_op->cont (p_op->anchor_wrap);
// this also cancels all running namestore operations
cleanup_plugin_operation (plugin_op_wrap);
return;
}
// check if all namestore operations are finished
GNUNET_free (ns_qe);
if (NULL == p_op->ns_qes_head)
{
// schedule the further execution, lets NAMESTORE clean up its operation list
GNUNET_SCHEDULER_add_now (&keyshare_distribution_finished, plugin_op_wrap);
}
}
static char *
get_label (const char *userSecret)
{
char *label;
struct GNUNET_HashCode hash;
struct GNUNET_CRYPTO_HashAsciiEncoded hashEnc;
// the label is the hash of the userSecret
GNUNET_CRYPTO_hash (userSecret, strlen (userSecret), &hash);
GNUNET_CRYPTO_hash_to_enc (&hash, &hashEnc);
label = GNUNET_strdup ((char *)hashEnc.encoding);
return label;
}
static int
distribute_keyshares (struct ESCROW_PluginOperationWrapper *plugin_op_wrap,
sss_Keyshare *keyshares)
{
struct ESCROW_GnsPluginOperation *p_op;
struct GNUNET_NAMESTORE_Handle *ns_h;
struct NamestoreQueueEntry *curr_ns_qe;
struct PkEntry *curr_pk;
char *curr_label;
struct GNUNET_GNSRECORD_Data curr_rd[1];
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Distributing keyshares\n");
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
ns_h = GNUNET_NAMESTORE_connect (p_op->h->cfg);
p_op->ns_h = ns_h;
for (curr_pk = p_op->escrow_pks_head; NULL != curr_pk; curr_pk = curr_pk->next)
{
curr_label = get_label (p_op->userSecret);
curr_ns_qe = GNUNET_new (struct NamestoreQueueEntry);
curr_rd[0].data_size = sizeof (sss_Keyshare);
curr_rd[0].data = keyshares[curr_pk->i];
curr_rd[0].record_type = GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE;
curr_rd[0].flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
// TODO: config param?
curr_rd[0].expiration_time = 30 * 24 * GNUNET_TIME_relative_get_hour_().rel_value_us;
curr_ns_qe->plugin_op_wrap = plugin_op_wrap;
curr_ns_qe->ns_qe = GNUNET_NAMESTORE_records_store (ns_h,
&curr_pk->pk,
curr_label,
1,
curr_rd,
&keyshare_distributed,
curr_ns_qe);
GNUNET_CONTAINER_DLL_insert_tail (p_op->ns_qes_head,
p_op->ns_qes_tail,
curr_ns_qe);
GNUNET_free (curr_label);
}
return GNUNET_OK;
}
void
escrow_ids_finished (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
{
struct ESCROW_GnsPluginOperation *p_op;
sss_Keyshare *keyshares;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All escrow identities created\n");
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
/* split the private key (SSS) */
keyshares = split_private_key (p_op);
if (NULL == keyshares)
{
p_op->anchor_wrap->anchor = NULL;
p_op->anchor_wrap->emsg = _ ("Failed to split the key!\n");
start_cont (plugin_op_wrap);
return;
}
/* distribute the shares to the identities */
if (GNUNET_OK != distribute_keyshares (plugin_op_wrap, keyshares))
{
p_op->anchor_wrap->anchor = NULL;
p_op->anchor_wrap->emsg = _ ("Failed to distribute the keyshares!\n");
start_cont (plugin_op_wrap);
return;
}
/* operation continues in keyshare_distribution_finished
after all keyshares have been distributed */
}
void
escrow_id_created (void *cls,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
const char *emsg)
{
struct IdentityOperationEntry *id_op = cls;
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
struct ESCROW_GnsPluginOperation *p_op;
struct PkEntry *pk_entry;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Escrow identity %d created\n", id_op->i);
plugin_op_wrap = id_op->plugin_op_wrap;
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
if (NULL == pk)
{
if (NULL != emsg)
{
fprintf (stderr,
"Identity create operation returned with error: %s\n",
emsg);
p_op->anchor_wrap->emsg = _ ("Identity create failed!\n");
}
else
p_op->anchor_wrap->emsg = _ ("Failed to create ego!\n");
p_op->anchor_wrap->anchor = NULL;
p_op->cont (p_op->anchor_wrap);
// this also cancels all running identity operations
cleanup_plugin_operation (plugin_op_wrap);
return;
}
/* escrow identity successfully created */
GNUNET_CONTAINER_DLL_remove (p_op->id_ops_head,
p_op->id_ops_tail,
id_op);
/* insert pk into our list */
pk_entry = GNUNET_new (struct PkEntry);
pk_entry->pk = *pk;
pk_entry->i = id_op->i;
GNUNET_CONTAINER_DLL_insert_tail (p_op->escrow_pks_head,
p_op->escrow_pks_tail,
pk_entry);
GNUNET_free (id_op);
/* check if this was the last id_op */
p_op->escrow_id_counter++;
if (p_op->escrow_id_counter == p_op->shares)
{
escrow_ids_finished (plugin_op_wrap);
}
}
static uint8_t
count_digits (uint8_t n)
{
uint8_t i = 0;
do
{
i++;
n /= 10;
} while (n != 0);
return i;
}
static char *
get_escrow_id_name (const char *name,
uint8_t i)
{
char *str, *prefix, *number;
uint8_t j = 0;
prefix = "escrow-id_";
number = GNUNET_malloc (count_digits (i) + 1);
sprintf (number, "%d", i);
str = GNUNET_malloc (strlen (prefix)
+ strlen (name)
+ 1
+ strlen (number)
+ 1);
memcpy (str, prefix, strlen (prefix));
j += strlen (prefix);
memcpy (str + j, name, strlen (name));
j += strlen (name);
str[j++] = '_';
memcpy (str + j, number, strlen (number));
j += strlen (number);
str[j] = '\0';
GNUNET_free (number);
return str;
}
static int
escrow_id_exists (const char *name,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
{
struct EgoEntry *curr;
for (curr = ph.ego_head; NULL != curr; curr = curr->next)
{
if (0 == strcmp (name, curr->identifier))
{
if (0 == memcmp (&curr->ego->pk,
pk,
sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)))
return GNUNET_YES;
else // the escrow id's name exists for an ego, but the pk is wrong
return GNUNET_SYSERR;
}
}
return GNUNET_NO;
}
static struct GNUNET_CRYPTO_EcdsaPrivateKey *
derive_private_key (const char *name,
const char *password,
uint8_t i)
{
struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
static const char ctx[] = "gnunet-escrow-id-ctx";
pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
GNUNET_CRYPTO_kdf (pk,
sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
ctx, strlen (ctx),
password, strlen (password),
name, strlen (name),
&i, 1,
NULL);
pk->d[0] &= 248;
pk->d[31] &= 127;
pk->d[31] |= 64;
return pk;
}
static void
handle_existing_wrong_ego_deletion (void *cls,
const char *emsg)
{
struct IdentityOperationEntry *curr_id_op = cls;
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
struct ESCROW_GnsPluginOperation *p_op;
plugin_op_wrap = curr_id_op->plugin_op_wrap;
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
if (NULL != emsg)
{
fprintf (stderr,
"Identity create operation returned with error: %s\n",
emsg);
p_op->anchor_wrap->emsg = _ ("Identity delete of wrong existing ego failed!\n");
p_op->anchor_wrap->anchor = NULL;
p_op->cont (p_op->anchor_wrap);
// this also cancels all running identity operations
cleanup_plugin_operation (plugin_op_wrap);
return;
}
/* no error occured, so create the new identity */
// the IdentityOperationEntry is reused, so only the id_op is updated
curr_id_op->id_op = GNUNET_IDENTITY_create (identity_handle,
curr_id_op->name,
curr_id_op->pk,
&escrow_id_created,
curr_id_op);
}
static void
create_escrow_identities (struct ESCROW_PluginOperationWrapper *plugin_op_wrap,
const char *name)
{
struct ESCROW_GnsPluginOperation *p_op;
struct GNUNET_CRYPTO_EcdsaPrivateKey *curr_pk;
char *curr_name;
struct IdentityOperationEntry *curr_id_op;
struct PkEntry *curr_pk_entry;
int exists_ret;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating escrow identities\n");
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
for (uint8_t i = 0; i < p_op->shares; i++)
{
curr_pk = derive_private_key (name, p_op->userSecret, i);
curr_name = get_escrow_id_name (name, i);
// check if the escrow identity already exists
exists_ret = escrow_id_exists (curr_name, curr_pk);
if (GNUNET_SYSERR == exists_ret)
{
/* an ego with identifier name but the wrong pk exists, delete it first */
curr_id_op = GNUNET_new (struct IdentityOperationEntry);
curr_id_op->pk = curr_pk;
curr_id_op->name = curr_name;
curr_id_op->i = i;
curr_id_op->plugin_op_wrap = plugin_op_wrap;
curr_id_op->id_op = GNUNET_IDENTITY_delete (identity_handle,
curr_name,
&handle_existing_wrong_ego_deletion,
curr_id_op);
GNUNET_CONTAINER_DLL_insert (p_op->id_ops_head,
p_op->id_ops_tail,
curr_id_op);
}
else if (GNUNET_YES == exists_ret)
{
// the escrow id already exists, so insert the pk into our list
curr_pk_entry = GNUNET_new (struct PkEntry);
curr_pk_entry->pk = *curr_pk;
curr_pk_entry->i = i;
GNUNET_CONTAINER_DLL_insert (p_op->escrow_pks_head,
p_op->escrow_pks_tail,
curr_pk_entry);
p_op->escrow_id_counter++;
if (p_op->escrow_id_counter == p_op->shares)
{
escrow_ids_finished (plugin_op_wrap);
}
}
else // GNUNET_NO
{
/* store the identity operation in our list */
curr_id_op = GNUNET_new (struct IdentityOperationEntry);
curr_id_op->pk = curr_pk;
curr_id_op->name = curr_name;
curr_id_op->i = i;
curr_id_op->plugin_op_wrap = plugin_op_wrap;
curr_id_op->id_op = GNUNET_IDENTITY_create (identity_handle,
curr_name,
curr_pk,
&escrow_id_created,
curr_id_op);
GNUNET_CONTAINER_DLL_insert (p_op->id_ops_head,
p_op->id_ops_tail,
curr_id_op);
}
}
}
static void
handle_config_load_error (struct ESCROW_PluginOperationWrapper *plugin_op_wrap,
char *emsg)
{
struct ESCROW_GnsPluginOperation *p_op;
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
if (NULL != p_op->anchor_wrap)
{
p_op->anchor_wrap->anchor = NULL;
p_op->anchor_wrap->emsg = emsg;
p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
return;
}
if (NULL != p_op->verify_wrap)
{
p_op->verify_wrap->verificationResult = GNUNET_ESCROW_INVALID;
p_op->verify_wrap->emsg = emsg;
p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
return;
}
if (NULL != p_op->ego_wrap)
{
p_op->ego_wrap->ego = NULL;
p_op->ego_wrap->emsg = emsg;
p_op->sched_task = GNUNET_SCHEDULER_add_now (&handle_restore_error, plugin_op_wrap);
return;
}
}
static int
load_keyshare_config (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
{
struct ESCROW_GnsPluginOperation *p_op;
unsigned long long shares, share_threshold;
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (p_op->h->cfg,
"escrow",
"gns_shares",
&shares))
{
handle_config_load_error (plugin_op_wrap,
"Number of shares not specified in config!");
return GNUNET_SYSERR;
}
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (p_op->h->cfg,
"escrow",
"gns_share_threshold",
&share_threshold))
{
handle_config_load_error (plugin_op_wrap,
"Share threshold not specified in config");
return GNUNET_SYSERR;
}
p_op->shares = (uint8_t)shares;
p_op->share_threshold = (uint8_t)share_threshold;
return GNUNET_OK;
}
static void
continue_start (void *cls)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
struct GNUNET_TIME_Relative delay;
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
if (ESCROW_PLUGIN_STATE_POST_INIT != ph.state)
{
delay.rel_value_us = 100 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
GNUNET_SCHEDULER_add_delayed (delay, &continue_start, plugin_op_wrap);
return;
}
/* load config */
if (GNUNET_OK != load_keyshare_config (plugin_op_wrap))
return;
/* create the escrow identities */
create_escrow_identities (plugin_op_wrap, p_op->ego->name);
/* operation continues in escrow_ids_finished
after all escrow identities are created */
}
/**
* Start the GNS escrow of the key
*
* @param h the handle for the escrow component
* @param ego the identity ego containing the private key
* @param userSecret the user secret (used for derivation of escrow identities)
* this has to be UNIQUE in the whole network!
* @param cb the function called upon completion
* @param op_id unique ID of the respective ESCROW_Operation
*
* @return plugin operation wrapper
*/
struct ESCROW_PluginOperationWrapper *
start_gns_key_escrow (struct GNUNET_ESCROW_Handle *h,
struct GNUNET_IDENTITY_Ego *ego,
const char *userSecret,
GNUNET_SCHEDULER_TaskCallback cb,
uint32_t op_id)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
struct ESCROW_GnsPluginOperation *p_op;
struct ESCROW_Plugin_AnchorContinuationWrapper *w;
struct GNUNET_TIME_Relative delay;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting GNS escrow\n");
// create a new GNS plugin operation (in a wrapper) and insert it into the DLL
plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_GnsPluginOperation);
GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
ph.plugin_op_tail,
plugin_op_wrap);
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
p_op->h = h;
p_op->cont = cb;
p_op->ego = ego;
w = GNUNET_new (struct ESCROW_Plugin_AnchorContinuationWrapper);
w->h = h;
w->op_id = op_id;
p_op->anchor_wrap = w;
if (NULL == ego || NULL == userSecret)
{
w->anchor = NULL;
if (NULL == ego)
w->emsg = _ ("ESCROW_put was called with ego == NULL\n");
else if (NULL == userSecret)
w->emsg = _ ("GNS escrow needs a user secret!\n");
p_op->sched_task = GNUNET_SCHEDULER_add_now (&start_cont, plugin_op_wrap);
return plugin_op_wrap;
}
p_op->pk = *GNUNET_IDENTITY_ego_get_private_key (ego);
p_op->userSecret = GNUNET_strdup (userSecret);
if (ESCROW_PLUGIN_STATE_POST_INIT == ph.state)
{
continue_start (plugin_op_wrap);
}
else
{
delay.rel_value_us = 200 * GNUNET_TIME_relative_get_millisecond_().rel_value_us;
GNUNET_SCHEDULER_add_delayed (delay, &continue_start, plugin_op_wrap);
}
return plugin_op_wrap;
}
static uint8_t
count_keyshares (sss_Keyshare *keyshares, uint8_t n)
{
uint8_t i, c;
sss_Keyshare null_ks;
memset (null_ks, 0, sizeof (sss_Keyshare));
c = 0;
for (i = 0; i < n; i++)
{
if (0 != memcmp (keyshares[i], &null_ks, sizeof (sss_Keyshare)))
c++;
}
return c;
}
static void
remove_empty_keyshares (sss_Keyshare *keyshares, uint8_t n)
{
uint8_t i, j;
sss_Keyshare null_ks;
memset (null_ks, 0, sizeof (sss_Keyshare));
for (i = j = 0; i < n; i++)
{
if (0 != memcmp (keyshares[i], &null_ks, sizeof (sss_Keyshare)))
{
memcpy (keyshares[j], keyshares[i], sizeof (sss_Keyshare));
j++;
}
}
}
static void
process_keyshares (void *cls)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
struct GNUNET_CRYPTO_EcdsaPrivateKey *pk;
uint8_t keyshares_count;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
/* check if enough keyshares have been restored */
keyshares_count = count_keyshares (p_op->restored_keyshares, p_op->shares);
if (keyshares_count < p_op->share_threshold)
{
/* the key cannot be restored */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"need %hhu shares, but could only get %hhu\n",
p_op->share_threshold,
keyshares_count);
if (NULL != p_op->verify_wrap) // this was called by a verify operation
{
p_op->verify_wrap->emsg =
_ ("key could not be restored, failed to get enough keyshares\n");
p_op->restore_pk_cont (p_op->restore_pk_cont_cls, NULL);
return;
}
if (NULL != p_op->ego_wrap) // this was called by a restore operation
{
p_op->ego_wrap->emsg =
_ ("key could not be restored, failed to get enough keyshares\n");
p_op->restore_pk_cont (p_op->restore_pk_cont_cls, NULL);
return;
}
}
/* combine the shares */
if (keyshares_count != p_op->shares)
remove_empty_keyshares (p_op->restored_keyshares, p_op->shares);
pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
sss_combine_keyshares (pk->d,
p_op->restored_keyshares,
keyshares_count);
p_op->restore_pk_cont (p_op->restore_pk_cont_cls, pk);
}
static void
process_gns_lookup_result (void *cls,
uint32_t rd_count,
const struct GNUNET_GNSRECORD_Data *rd)
{
struct GnsLookupRequestEntry *gns_lr = cls;
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
struct ESCROW_GnsPluginOperation *p_op;
sss_Keyshare keyshare;
char keyshare_string[64], *end;
plugin_op_wrap = gns_lr->plugin_op_wrap;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
/* remove gns_lr from our list */
GNUNET_CONTAINER_DLL_remove (p_op->gns_lrs_head,
p_op->gns_lrs_tail,
gns_lr);
/* cancel the timeout for that lookup */
GNUNET_CONTAINER_DLL_remove (p_op->tts_head,
p_op->tts_tail,
gns_lr->tt);
GNUNET_SCHEDULER_cancel (gns_lr->tt->tt);
GNUNET_free (gns_lr->tt);
if (1 != rd_count)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"did not get exactly _one_ record from GNS\n");
goto END;
}
if (sizeof (sss_Keyshare) != rd[0].data_size)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"the size of the GNS record differs from the size of a keyshare\n");
goto END;
}
GNUNET_memcpy (&keyshare,
rd[0].data,
rd[0].data_size);
end = GNUNET_STRINGS_data_to_string (&keyshare,
sizeof (sss_Keyshare),
keyshare_string,
sizeof (keyshare_string));
GNUNET_break (NULL != end);
*end = '\0';
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"got keyshare %s from GNS\n", keyshare_string);
GNUNET_memcpy (p_op->restored_keyshares[gns_lr->i],
&keyshare,
sizeof (sss_Keyshare));
END:
GNUNET_free (gns_lr);
// check if this was the last gns_lr, i.e. our list is empty
if (NULL == p_op->gns_lrs_head)
{
// schedule the further execution, lets GNS clean up its operation list
GNUNET_SCHEDULER_add_now (&process_keyshares, plugin_op_wrap);
}
}
static void
timeout_gns_request (void *cls)
{
struct TimeoutTaskEntry *curr_tt = cls;
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
struct ESCROW_GnsPluginOperation *p_op;
plugin_op_wrap = curr_tt->plugin_op_wrap;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
/* remove timeout task from our list */
GNUNET_CONTAINER_DLL_remove (p_op->tts_head,
p_op->tts_tail,
curr_tt);
/* cancel the GNS lookup and remove it from our list */
GNUNET_GNS_lookup_cancel (curr_tt->gns_lr->lr);
GNUNET_CONTAINER_DLL_remove (p_op->gns_lrs_head,
p_op->gns_lrs_tail,
curr_tt->gns_lr);
GNUNET_free (curr_tt->gns_lr);
GNUNET_free (curr_tt);
/* check if this was the last pending GNS lookup */
if (NULL == p_op->gns_lrs_head)
{
// no need to schedule, as the timeout is already scheduled
process_keyshares (plugin_op_wrap);
}
}
static char *
get_user_secret_from_anchor (const struct GNUNET_ESCROW_Anchor *anchor)
{
char *userSecret;
userSecret = GNUNET_malloc (anchor->size);
GNUNET_memcpy (userSecret, &anchor[1], anchor->size);
return userSecret;
}
static void
restore_private_key (struct ESCROW_PluginOperationWrapper *plugin_op_wrap,
struct GNUNET_ESCROW_Anchor *anchor,
PkContinuation cont,
void *cont_cls)
{
struct ESCROW_GnsPluginOperation *p_op;
struct GNUNET_CRYPTO_EcdsaPrivateKey *curr_escrow_pk;
struct GNUNET_CRYPTO_EcdsaPublicKey curr_escrow_pub;
char *label;
struct GnsLookupRequestEntry *curr_gns_lr;
struct GNUNET_TIME_Relative delay;
struct TimeoutTaskEntry *curr_tt;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
p_op->gns_h = GNUNET_GNS_connect (p_op->h->cfg);
p_op->restore_pk_cont = cont;
p_op->restore_pk_cont_cls = cont_cls;
p_op->restored_keyshares = GNUNET_malloc (sizeof (sss_Keyshare) * p_op->shares);
// ensure that the array is initialized with 0, as this is needed for counting the shares
memset (p_op->restored_keyshares, 0, sizeof (sss_Keyshare) * p_op->shares);
p_op->userSecret = get_user_secret_from_anchor (anchor);
label = get_label (p_op->userSecret);
// init delay to 2s
delay.rel_value_us = 2 * GNUNET_TIME_relative_get_second_().rel_value_us;
for (uint8_t i = 0; i < p_op->shares; i++)
{
curr_escrow_pk = derive_private_key (anchor->egoName, p_op->userSecret, i);
curr_gns_lr = GNUNET_new (struct GnsLookupRequestEntry);
curr_gns_lr->plugin_op_wrap = plugin_op_wrap;
curr_gns_lr->i = i;
GNUNET_CRYPTO_ecdsa_key_get_public (curr_escrow_pk, &curr_escrow_pub);
curr_gns_lr->lr = GNUNET_GNS_lookup (p_op->gns_h,
label,
&curr_escrow_pub,
GNUNET_GNSRECORD_TYPE_ESCROW_KEYSHARE,
GNUNET_GNS_LO_DEFAULT,
&process_gns_lookup_result,
curr_gns_lr);
GNUNET_CONTAINER_DLL_insert_tail (p_op->gns_lrs_head,
p_op->gns_lrs_tail,
curr_gns_lr);
/* start timeout for GNS lookup (cancels the lr if not yet finished) */
curr_tt = GNUNET_new (struct TimeoutTaskEntry);
curr_tt->gns_lr = curr_gns_lr;
curr_tt->plugin_op_wrap = plugin_op_wrap;
curr_tt->tt = GNUNET_SCHEDULER_add_delayed (delay,
&timeout_gns_request,
curr_tt);
GNUNET_CONTAINER_DLL_insert_tail (p_op->tts_head,
p_op->tts_tail,
curr_tt);
// set the timeout task for the current gns lr entry
curr_gns_lr->tt = curr_tt;
}
GNUNET_free (label);
}
static void
verify_restored_pk (void *cls,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
const struct GNUNET_CRYPTO_EcdsaPrivateKey *ego_pk;
int verificationResult;
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
if (NULL == pk)
verificationResult = GNUNET_ESCROW_INVALID;
else
{
ego_pk = GNUNET_IDENTITY_ego_get_private_key (p_op->ego);
verificationResult = memcmp (pk,
ego_pk,
sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey))
== 0 ? GNUNET_ESCROW_VALID : GNUNET_ESCROW_INVALID;
}
// check if all shares could be restored
if (GNUNET_ESCROW_VALID == verificationResult &&
count_keyshares (p_op->restored_keyshares, p_op->shares) < p_op->shares)
verificationResult = GNUNET_ESCROW_SHARES_MISSING;
p_op->verify_wrap->verificationResult = verificationResult;
verify_cont (plugin_op_wrap);
}
/**
* Verify the GNS escrow of the key
*
* @param h the handle for the escrow component
* @param ego the identity ego containing the private key
* @param anchor the escrow anchor needed to restore the key
* @param cb the function called upon completion
* @param op_id unique ID of the respective ESCROW_Operation
*
* @return plugin operation wrapper
*/
struct ESCROW_PluginOperationWrapper *
verify_gns_key_escrow (struct GNUNET_ESCROW_Handle *h,
struct GNUNET_IDENTITY_Ego *ego,
struct GNUNET_ESCROW_Anchor *anchor,
GNUNET_SCHEDULER_TaskCallback cb,
uint32_t op_id)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
struct ESCROW_GnsPluginOperation *p_op;
struct ESCROW_Plugin_VerifyContinuationWrapper *w;
// create a new GNS plugin operation (in a wrapper) and insert it into the DLL
plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_GnsPluginOperation);
GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
ph.plugin_op_tail,
plugin_op_wrap);
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
p_op->h = h;
p_op->cont = cb;
p_op->ego = ego;
p_op->egoName = GNUNET_strdup (ego->name);
w = GNUNET_new (struct ESCROW_Plugin_VerifyContinuationWrapper);
w->h = h;
w->op_id = op_id;
p_op->verify_wrap = w;
if (NULL == ego)
{
w->verificationResult = GNUNET_ESCROW_INVALID;
w->emsg = _ ("ESCROW_verify was called with ego == NULL!\n");
p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
return plugin_op_wrap;
}
if (0 != strcmp (ego->name, anchor->egoName))
{
w->verificationResult = GNUNET_ESCROW_INVALID;
w->emsg = _ ("This anchor was not created when putting ego that in escrow!\n");
p_op->sched_task = GNUNET_SCHEDULER_add_now (&verify_cont, plugin_op_wrap);
return plugin_op_wrap;
}
/* load config */
if (GNUNET_OK != load_keyshare_config (plugin_op_wrap))
return plugin_op_wrap;
restore_private_key (plugin_op_wrap,
anchor,
&verify_restored_pk,
plugin_op_wrap);
return plugin_op_wrap;
}
void
ego_created (const struct GNUNET_IDENTITY_Ego *ego)
{
struct ESCROW_PluginOperationWrapper *curr;
struct ESCROW_GnsPluginOperation *curr_p_op;
char *ego_pk_string, *curr_pk_string;
ego_pk_string = GNUNET_CRYPTO_ecdsa_private_key_to_string (&ego->pk);
for (curr = ph.plugin_op_head; NULL != curr; curr = curr->next)
{
curr_p_op = (struct ESCROW_GnsPluginOperation *)curr->plugin_op;
curr_pk_string = GNUNET_CRYPTO_ecdsa_private_key_to_string (&curr_p_op->pk);
// compare the strings of the private keys
if (0 == strcmp (ego_pk_string, curr_pk_string))
{
// the ego was created due to a restore operation that is not yet finished
curr_p_op->ego_wrap->ego = ego;
curr_p_op->cont (curr_p_op->ego_wrap);
cleanup_plugin_operation (curr);
GNUNET_free (curr_pk_string);
GNUNET_free (ego_pk_string);
return;
}
GNUNET_free (curr_pk_string);
}
GNUNET_free (ego_pk_string);
}
static void
id_create_finished (void *cls,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk,
const char *emsg)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
if (NULL == pk)
{
if (NULL != emsg)
{
fprintf (stderr,
"Identity create operation returned with error: %s\n",
emsg);
p_op->ego_wrap->emsg = _ ("Identity create failed!\n");
}
else
p_op->ego_wrap->emsg = _ ("Failed to create ego!\n");
p_op->ego_wrap->ego = NULL;
p_op->cont (p_op->ego_wrap);
return;
}
/* no error occurred, p_op->restore_cont will be called in ego_created, which
is called from ESCROW_list_ego after adding the new ego to our list */
p_op->pk = *pk;
}
static void
restore_ego_from_pk (void *cls,
const struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap = cls;
struct ESCROW_GnsPluginOperation *p_op;
p_op = (struct ESCROW_GnsPluginOperation*)plugin_op_wrap->plugin_op;
if (NULL == pk)
{
p_op->ego_wrap->ego = NULL;
handle_restore_error (plugin_op_wrap);
return;
}
p_op->id_op = GNUNET_IDENTITY_create (identity_handle,
p_op->egoName,
pk,
&id_create_finished,
plugin_op_wrap);
}
/**
* Restore the key from GNS escrow
*
* @param h the handle for the escrow component
* @param anchor the escrow anchor needed to restore the key
* @param cb the function called upon completion
* @param op_id unique ID of the respective ESCROW_Operation
*
* @return plugin operation wrapper
*/
struct ESCROW_PluginOperationWrapper *
restore_gns_key_escrow (struct GNUNET_ESCROW_Handle *h,
struct GNUNET_ESCROW_Anchor *anchor,
GNUNET_SCHEDULER_TaskCallback cb,
uint32_t op_id)
{
struct ESCROW_PluginOperationWrapper *plugin_op_wrap;
struct ESCROW_GnsPluginOperation *p_op;
struct ESCROW_Plugin_EgoContinuationWrapper *w;
// create a new GNS plugin operation (in a wrapper) and insert it into the DLL
plugin_op_wrap = GNUNET_new (struct ESCROW_PluginOperationWrapper);
plugin_op_wrap->plugin_op = GNUNET_new (struct ESCROW_GnsPluginOperation);
GNUNET_CONTAINER_DLL_insert_tail (ph.plugin_op_head,
ph.plugin_op_tail,
plugin_op_wrap);
p_op = (struct ESCROW_GnsPluginOperation *)plugin_op_wrap->plugin_op;
p_op->h = h;
// set cont here (has to be scheduled from the IDENTITY service when it finished)
p_op->cont = cb;
p_op->egoName = GNUNET_strdup (anchor->egoName);
w = GNUNET_new (struct ESCROW_Plugin_EgoContinuationWrapper);
w->h = h;
w->op_id = op_id;
p_op->ego_wrap = w;
if (NULL == anchor)
{
w->ego = NULL;
w->emsg = _ ("ESCROW_get was called with anchor == NULL!\n");
// schedule handle_restore_error, which calls the callback and cleans up
p_op->sched_task = GNUNET_SCHEDULER_add_now (&handle_restore_error, plugin_op_wrap);
return plugin_op_wrap;
}
/* load config */
if (GNUNET_OK != load_keyshare_config (plugin_op_wrap))
return plugin_op_wrap;
restore_private_key (plugin_op_wrap,
anchor,
&restore_ego_from_pk,
plugin_op_wrap);
return plugin_op_wrap;
}
/**
* Get the status of a GNS escrow
*
* @param h the handle for the escrow component
* @param ego the identity ego of which the status has to be obtained
*
* @return the status of the escrow packed into a GNUNET_ESCROW_Status struct
*/
struct GNUNET_ESCROW_Status *
gns_get_status (struct GNUNET_ESCROW_Handle *h,
struct GNUNET_IDENTITY_Ego *ego)
{
return ESCROW_get_escrow_status (h, ego);
}
/**
* Cancel a GNS plugin operation.
*
* @param plugin_op_wrap the plugin operation wrapper containing the operation
*/
void
cancel_gns_operation (struct ESCROW_PluginOperationWrapper *plugin_op_wrap)
{
struct ESCROW_PluginOperationWrapper *curr;
for (curr = ph.plugin_op_head; NULL != curr; curr = curr->next)
{
if (curr == plugin_op_wrap)
{
GNUNET_CONTAINER_DLL_remove (ph.plugin_op_head,
ph.plugin_op_tail,
curr);
cleanup_plugin_operation (curr);
return;
}
}
}
/**
* IdentityInitContinuation for the GNS plugin
*/
void
gns_cont_init ()
{
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNS plugin initialized\n");
}
/**
* Entry point for the plugin.
*
* @param cls Config info
*
* @return the exported block API
*/
void *
libgnunet_plugin_escrow_gns_init (void *cls)
{
struct GNUNET_ESCROW_KeyPluginFunctions *api;
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
api = GNUNET_new (struct GNUNET_ESCROW_KeyPluginFunctions);
api->start_key_escrow = &start_gns_key_escrow;
api->verify_key_escrow = &verify_gns_key_escrow;
api->restore_key = &restore_gns_key_escrow;
api->get_status = &gns_get_status;
api->cancel_plugin_operation = &cancel_gns_operation;
ph.state = ESCROW_PLUGIN_STATE_INIT;
ph.id_init_cont = &gns_cont_init;
ph.ego_create_cont = &ego_created;
identity_handle = GNUNET_IDENTITY_connect (cfg,
&ESCROW_list_ego,
&ph);
return api;
}
/**
* Exit point from the plugin.
*
* @param cls the return value from #libgnunet_plugin_block_test_init()
*
* @return NULL
*/
void *
libgnunet_plugin_escrow_gns_done (void *cls)
{
struct GNUNET_ESCROW_KeyPluginFunctions *api = cls;
GNUNET_free (api);
GNUNET_IDENTITY_disconnect (identity_handle);
ESCROW_cleanup_ego_list (&ph);
return NULL;
}
/* end of plugin_escrow_gns.c */