/**
 * We obtained a result for our query to the shorten zone from
 * the namestore.  Try to decrypt.
 *
 * @param cls the handle to our shorten operation
 * @param block resulting encrypted block
 */
static void
process_pseu_block_ns (void *cls,
		       const struct GNUNET_GNSRECORD_Block *block)
{
  struct GetPseuAuthorityHandle *gph = cls;
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;

  gph->namecache_task = NULL;
  if (NULL == block)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Namecache did not return information for label `%s' \n",
                gph->current_label);
    process_pseu_lookup_ns (gph, 0, NULL);
    return;
  }
  GNUNET_CRYPTO_ecdsa_key_get_public (&gph->shorten_zone_key,
				    &pub);
  if (GNUNET_OK !=
      GNUNET_GNSRECORD_block_decrypt (block,
				      &pub,
				      gph->current_label,
				      &process_pseu_lookup_ns,
				      gph))
  {
    GNUNET_break (0);
    free_get_pseu_authority_handle (gph);
    return;
  }
}
Beispiel #2
0
static void
adv_cont (void *cls, const struct GNUNET_FS_Uri *uri, const char *emsg)
{
  struct GNUNET_CONTAINER_MetaData *meta;
  struct GNUNET_CRYPTO_EcdsaPrivateKey *ns;
  struct GNUNET_FS_BlockOptions bo;

  if (NULL != emsg)
  {
    FPRINTF (stderr, "Error publishing: %s\n", emsg);
    err = 1;
    GNUNET_FS_stop (fs);
    return;
  }
  ns = GNUNET_CRYPTO_ecdsa_key_create ();
  meta = GNUNET_CONTAINER_meta_data_create ();
  sks_expect_uri = GNUNET_FS_uri_dup (uri);
  bo.content_priority = 1;
  bo.anonymity_level = 1;
  bo.replication_level = 0;
  bo.expiration_time =
      GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES);
  GNUNET_CRYPTO_ecdsa_key_get_public (ns, &nsid);
  GNUNET_FS_publish_sks (fs, ns, "this", "next", meta, uri,
                         &bo, GNUNET_FS_PUBLISH_OPTION_NONE, &sks_cont, NULL);
  GNUNET_CONTAINER_meta_data_destroy (meta);
  GNUNET_free (ns);
}
static void
run (void *cls, char *const *args, const char *cfgfile,
     const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  struct GNUNET_GNSRECORD_Block *block;
  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;

  /* load privat key */
  char *hostkey_file;
  GNUNET_asprintf(&hostkey_file,
                  "zonefiles%s%s",
                  DIR_SEPARATOR_STR,
                  "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey");
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Using zonekey file `%s'\n",
              hostkey_file);
  privkey = GNUNET_CRYPTO_ecdsa_key_create_from_file(hostkey_file);
  GNUNET_free (hostkey_file);
  GNUNET_assert (privkey != NULL);
  struct GNUNET_TIME_Absolute expire = GNUNET_TIME_absolute_get();
  /* get public key */
  GNUNET_CRYPTO_ecdsa_key_get_public(privkey, &pubkey);

  /* create record */
  s_name = "DUMMY.dummy.gnunet";
  s_rd = create_record (RECORDS);

  /* Create block */
  GNUNET_assert (NULL != (block = GNUNET_GNSRECORD_block_create (privkey, expire,s_name, s_rd, RECORDS)));
  GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_verify (block));
  GNUNET_assert (GNUNET_OK == GNUNET_GNSRECORD_block_decrypt (block, &pubkey, s_name, &rd_decrypt_cb, s_name));

  GNUNET_free (block);
}
Beispiel #4
0
/**
 * Get the identifier (public key) of an ego.
 *
 * @param ego identity handle with the private key
 * @param pk set to ego's public key
 */
void
GNUNET_IDENTITY_ego_get_public_key (const struct GNUNET_IDENTITY_Ego *ego,
				    struct GNUNET_CRYPTO_EcdsaPublicKey *pk)
{
  GNUNET_CRYPTO_ecdsa_key_get_public (ego->pk,
				    pk);
}
Beispiel #5
0
/**
 * Calculate the DHT query for a given @a label in a given @a zone.
 *
 * @param zone private key of the zone
 * @param label label of the record
 * @param query hash to use for the query
 */
void
GNUNET_GNSRECORD_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
					 const char *label,
					 struct GNUNET_HashCode *query)
{
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;

  GNUNET_CRYPTO_ecdsa_key_get_public (zone, &pub);
  GNUNET_GNSRECORD_query_from_public_key (&pub, label, query);
}
Beispiel #6
0
/**
 * Obtain the ego representing 'anonymous' users.
 *
 * @return handle for the anonymous user, must not be freed
 */
const struct GNUNET_IDENTITY_Ego *
GNUNET_IDENTITY_ego_get_anonymous ()
{
  static struct GNUNET_IDENTITY_Ego anon;
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;

  if (NULL != anon.pk)
    return &anon;
  anon.pk = (struct GNUNET_CRYPTO_EcdsaPrivateKey *) GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
  GNUNET_CRYPTO_ecdsa_key_get_public (anon.pk,
				    &pub);
  GNUNET_CRYPTO_hash (&pub, sizeof (pub), &anon.id);
  return &anon;
}
static void
run (void *cls,
     const struct GNUNET_CONFIGURATION_Handle *cfg,
     struct GNUNET_TESTING_Peer *peer)
{
  struct GNUNET_GNSRECORD_Data rd;
  char *hostkey_file;

  directory = NULL;
  GNUNET_CONFIGURATION_get_value_string(cfg, "PATHS", "GNUNET_TEST_HOME", &directory);
  GNUNET_DISK_directory_remove (directory);

  update_performed = GNUNET_NO;
  endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
						&endbadly, NULL);
  GNUNET_asprintf (&hostkey_file,
		   "zonefiles%s%s",
		   DIR_SEPARATOR_STR,
		   "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey");
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Using zonekey file `%s' \n", hostkey_file);
  privkey = GNUNET_CRYPTO_ecdsa_key_create_from_file (hostkey_file);
  GNUNET_free (hostkey_file);
  GNUNET_assert (privkey != NULL);
  GNUNET_CRYPTO_ecdsa_key_get_public (privkey, &pubkey);

  rd.flags = GNUNET_GNSRECORD_RF_NONE;
  rd.expiration_time = GNUNET_TIME_absolute_get().abs_value_us + 1000000000;
  rd.record_type = TEST_RECORD_TYPE;
  rd.data_size = TEST_RECORD_DATALEN;
  rd.data = GNUNET_malloc (TEST_RECORD_DATALEN);
  memset ((char *) rd.data, TEST_RECORD_DATA, TEST_RECORD_DATALEN);

  nsh = GNUNET_NAMESTORE_connect (cfg);
  GNUNET_break (NULL != nsh);
  nch = GNUNET_NAMECACHE_connect (cfg);
  GNUNET_break (NULL != nch);
  nsqe = GNUNET_NAMESTORE_records_store (nsh,
                                         privkey, name,
                                         1, &rd,
                                         &put_cont, (void *) name);
  if (NULL == nsqe)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  	      _("Namestore cannot store no block\n"));
  }
  GNUNET_free ((void *)rd.data);
}
/**
 * Function to handle call request from the client
 *
 * @param cls the `struct Line` the message is about
 * @param msg the message from the client
 */
static void
handle_client_call_message (void *cls,
                            const struct ClientCallMessage *msg)
{
  struct Line *line = cls;
  struct Channel *ch;
  struct GNUNET_MQ_Envelope *e;
  struct CadetPhoneRingMessage *ring;
  struct CadetPhoneRingInfoPS rs;

  line->line_port = msg->line_port;
  rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING);
  rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS));
  rs.line_port = line->line_port;
  rs.target_peer = msg->target;
  rs.expiration_time
    = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT));

  ch = GNUNET_new (struct Channel);
  ch->line = line;
  GNUNET_CONTAINER_DLL_insert (line->channel_head,
                               line->channel_tail,
                               ch);
  ch->status = CS_CALLER_CALLING;
  ch->channel = GNUNET_CADET_channel_create (cadet,
                                             ch,
                                             &msg->target,
                                             &msg->line_port,
                                             GNUNET_CADET_OPTION_RELIABLE);
  ch->mq = GNUNET_CADET_mq_create (ch->channel);
  e = GNUNET_MQ_msg (ring,
                     GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING);
  GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id,
                                      &ring->caller_id);
  ring->expiration_time = rs.expiration_time;
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id,
                                           &rs.purpose,
                                           &ring->signature));
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Sending RING message via CADET\n");
  GNUNET_MQ_send (ch->mq,
                  e);
  GNUNET_SERVICE_client_continue (line->client);
}
Beispiel #9
0
/**
 * If necessary, connect to the datastore and remove the KBlocks.
 *
 * @param uc context for the unindex operation.
 */
void
GNUNET_FS_unindex_do_remove_kblocks_ (struct GNUNET_FS_UnindexContext *uc)
{
  const char *keyword;
  const struct GNUNET_CRYPTO_EcdsaPrivateKey *anon;
  struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
  struct GNUNET_CRYPTO_EcdsaPublicKey dpub;

  if (NULL == uc->dsh)
    uc->dsh = GNUNET_DATASTORE_connect (uc->h->cfg);
  if (NULL == uc->dsh)
  {
    uc->state = UNINDEX_STATE_ERROR;
    uc->emsg = GNUNET_strdup (_("Failed to connect to `datastore' service."));
    GNUNET_FS_unindex_sync_ (uc);
    signal_unindex_error (uc);
    return;
  }
  if ( (NULL == uc->ksk_uri) ||
       (uc->ksk_offset >= uc->ksk_uri->data.ksk.keywordCount) )
  {
    unindex_finish (uc);
    return;
  }
  anon = GNUNET_CRYPTO_ecdsa_key_get_anonymous ();
  GNUNET_CRYPTO_ecdsa_key_get_public (anon,
                                      &anon_pub);
  keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1];
  GNUNET_CRYPTO_ecdsa_public_key_derive (&anon_pub,
                                         keyword,
                                         "fs-ublock",
                                         &dpub);
  GNUNET_CRYPTO_hash (&dpub,
		      sizeof (dpub),
		      &uc->uquery);
  uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
				      uc->roff++,
				      &uc->uquery,
				      GNUNET_BLOCK_TYPE_FS_UBLOCK,
				      0 /* priority */,
                                      1 /* queue size */,
				      GNUNET_TIME_UNIT_FOREVER_REL,
				      &process_kblock_for_unindex,
				      uc);
}
/**
 * Lookup in the namecache for the shorten zone the given label.
 *
 * @param gph the handle to our shorten operation
 * @param label the label to lookup
 */
static void
perform_nick_lookup (struct GetPseuAuthorityHandle *gph,
		     const char *label)
{
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  struct GNUNET_HashCode query;

  GNUNET_CRYPTO_ecdsa_key_get_public (&gph->shorten_zone_key,
				    &pub);
  GNUNET_free_non_null (gph->current_label);
  gph->current_label = GNUNET_strdup (label);
  GNUNET_GNSRECORD_query_from_public_key (&pub,
					  label,
					  &query);
  gph->namecache_task = GNUNET_NAMECACHE_lookup_block (namecache_handle,
						       &query,
						       &process_pseu_block_ns,
						       gph);
}
static void
put_cont (void *cls, int32_t success, const char *emsg)
{
  const char *name = cls;
  struct GNUNET_HashCode derived_hash;
  struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;

  nsqe = NULL;
  GNUNET_assert (NULL != cls);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Name store added record for `%s': %s\n",
	      name,
	      (success == GNUNET_OK) ? "SUCCESS" : "FAIL");

  /* Create derived hash */
  GNUNET_CRYPTO_ecdsa_key_get_public (privkey, &pubkey);
  GNUNET_GNSRECORD_query_from_public_key (&pubkey, name, &derived_hash);

  ncqe = GNUNET_NAMECACHE_lookup_block (nch, &derived_hash,
                                        &name_lookup_proc, (void *) name);
}
/**
 * Start shortening algorithm, try to allocate a nice short
 * canonical name for @a pub in @a shorten_zone, using
 * @a original_label as one possible suggestion.
 *
 * @param original_label original label for the zone
 * @param suggested_label suggested label for the zone
 * @param pub public key of the zone to shorten
 * @param shorten_zone private key of the target zone for the new record
 */
void
GNS_shorten_start (const char *original_label,
                   const char *suggested_label,
		   const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
		   const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone)
{
  struct GetPseuAuthorityHandle *gph;
  struct GNUNET_CRYPTO_EcdsaPublicKey shorten_pub;

  if (strlen (original_label) > GNUNET_DNSPARSER_MAX_LABEL_LENGTH)
  {
    GNUNET_break (0);
    return;
  }
  GNUNET_CRYPTO_ecdsa_key_get_public (shorten_zone, &shorten_pub);
  if (0 == memcmp (&shorten_pub, pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
  {
    /* Do not shorten the shorten zone */
    return;
  }

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Starting shortening process for `%s' with old label `%s' and suggested nickname `%s'\n",
	      GNUNET_GNSRECORD_z2s (pub),
	      original_label, suggested_label);
  gph = GNUNET_new (struct GetPseuAuthorityHandle);
  gph->shorten_zone_key = *shorten_zone;
  gph->target_zone = *pub;
  gph->suggested_label = GNUNET_strdup (suggested_label);
  strcpy (gph->label, original_label);
  GNUNET_CONTAINER_DLL_insert (gph_head, gph_tail, gph);
  /* first, check if we *already* have a record for this zone */
  gph->namestore_task = GNUNET_NAMESTORE_zone_to_name (namestore_handle,
                                                       shorten_zone,
                                                       pub,
                                                       &zone_to_name_error_cb,
                                                       gph,
                                                       &process_zone_to_name_discover,
                                                       gph);
}
static void
run (void *cls,
     const struct GNUNET_CONFIGURATION_Handle *cfg,
     struct GNUNET_TESTING_Peer *peer)
{
  char *hostkey_file;
  const char * name = "dummy.dummy.gnunet";

  directory = NULL;
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONFIGURATION_get_value_string(cfg, "PATHS", "GNUNET_TEST_HOME", &directory));
  GNUNET_DISK_directory_remove (directory);

  endbadly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
						&endbadly, NULL);
  GNUNET_asprintf (&hostkey_file,
		   "zonefiles%s%s",
		   DIR_SEPARATOR_STR,
		   "N0UJMP015AFUNR2BTNM3FKPBLG38913BL8IDMCO2H0A1LIB81960.zkey");
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Using zonekey file `%s' \n",
              hostkey_file);
  privkey = GNUNET_CRYPTO_ecdsa_key_create_from_file (hostkey_file);
  GNUNET_free (hostkey_file);
  GNUNET_assert (privkey != NULL);
  GNUNET_CRYPTO_ecdsa_key_get_public (privkey, &pubkey);

  nsh = GNUNET_NAMESTORE_connect (cfg);
  GNUNET_break (NULL != nsh);
  nsqe = GNUNET_NAMESTORE_records_store (nsh, privkey, name,
                                         0, NULL,
                                         &put_cont, (void *) name);
  if (NULL == nsqe)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  	      _("Namestore cannot store no block\n"));
  }
}
/**
 * Publish a UBlock.
 *
 * @param h handle to the file sharing subsystem
 * @param dsh datastore handle to use for storage operation
 * @param label identifier to use
 * @param ulabel update label to use, may be an empty string for none
 * @param ns namespace to publish in
 * @param meta metadata to use
 * @param uri URI to refer to in the UBlock
 * @param bo per-block options
 * @param options publication options
 * @param cont continuation
 * @param cont_cls closure for @a cont
 * @return NULL on error (@a cont will still be called)
 */
struct GNUNET_FS_PublishUblockContext *
GNUNET_FS_publish_ublock_ (struct GNUNET_FS_Handle *h,
			   struct GNUNET_DATASTORE_Handle *dsh,
			   const char *label,
			   const char *ulabel,
			   const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns,
			   const struct GNUNET_CONTAINER_MetaData *meta,
			   const struct GNUNET_FS_Uri *uri,
			   const struct GNUNET_FS_BlockOptions *bo,
			   enum GNUNET_FS_PublishOptions options,
			   GNUNET_FS_UBlockContinuation cont, void *cont_cls)
{
  struct GNUNET_FS_PublishUblockContext *uc;
  struct GNUNET_HashCode query;
  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  struct GNUNET_CRYPTO_SymmetricSessionKey skey;
  struct GNUNET_CRYPTO_EcdsaPrivateKey *nsd;
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  char *uris;
  size_t size;
  char *kbe;
  char *sptr;
  ssize_t mdsize;
  size_t slen;
  size_t ulen;
  struct UBlock *ub_plain;
  struct UBlock *ub_enc;

  /* compute ublock to publish */
  if (NULL == meta)
    mdsize = 0;
  else
    mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
  GNUNET_assert (mdsize >= 0);
  uris = GNUNET_FS_uri_to_string (uri);
  slen = strlen (uris) + 1;
  if (NULL == ulabel)
    ulen = 1;
  else
    ulen = strlen (ulabel) + 1;
  size = mdsize + sizeof (struct UBlock) + slen + ulen;
  if (size > MAX_UBLOCK_SIZE)
  {
    size = MAX_UBLOCK_SIZE;
    mdsize = size - sizeof (struct UBlock) - (slen + ulen);
  }
  ub_plain = GNUNET_malloc (size);
  kbe = (char *) &ub_plain[1];
  if (NULL != ulabel)
    memcpy (kbe, ulabel, ulen);
  kbe += ulen;
  memcpy (kbe, uris, slen);
  kbe += slen;
  GNUNET_free (uris);
  sptr = kbe;
  if (NULL != meta)
    mdsize =
      GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, mdsize,
					    GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
  if (-1 == mdsize)
  {
    GNUNET_break (0);
    GNUNET_free (ub_plain);
    cont (cont_cls, _("Internal error."));
    return NULL;
  }
  size = sizeof (struct UBlock) + slen + mdsize + ulen;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Publishing under identifier `%s'\n",
              label);
  /* get public key of the namespace */
  GNUNET_CRYPTO_ecdsa_key_get_public (ns,
				    &pub);
  derive_ublock_encryption_key (&skey, &iv,
				label, &pub);

  /* encrypt ublock */
  ub_enc = GNUNET_malloc (size);
  GNUNET_CRYPTO_symmetric_encrypt (&ub_plain[1],
			     ulen + slen + mdsize,
			     &skey, &iv,
                             &ub_enc[1]);
  GNUNET_free (ub_plain);
  ub_enc->purpose.size = htonl (ulen + slen + mdsize +
				sizeof (struct UBlock)
				- sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
  ub_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK);

  /* derive signing-key from 'label' and public key of the namespace */
  nsd = GNUNET_CRYPTO_ecdsa_private_key_derive (ns, label, "fs-ublock");
  GNUNET_CRYPTO_ecdsa_key_get_public (nsd,
				    &ub_enc->verification_key);
  GNUNET_assert (GNUNET_OK ==
		 GNUNET_CRYPTO_ecdsa_sign (nsd,
					 &ub_enc->purpose,
					 &ub_enc->signature));
  GNUNET_CRYPTO_hash (&ub_enc->verification_key,
		      sizeof (ub_enc->verification_key),
		      &query);
  GNUNET_free (nsd);

  uc = GNUNET_new (struct GNUNET_FS_PublishUblockContext);
  uc->cont = cont;
  uc->cont_cls = cont_cls;
  uc->qre =
    GNUNET_DATASTORE_put (dsh, 0, &query,
			  ulen + slen + mdsize + sizeof (struct UBlock),
			  ub_enc, GNUNET_BLOCK_TYPE_FS_UBLOCK,
			  bo->content_priority, bo->anonymity_level,
			  bo->replication_level, bo->expiration_time,
			  -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT,
			  &ublock_put_cont, uc);
  return uc;
}
Beispiel #15
0
/**
 * Function called with the result from the check if the namestore
 * service is actually running.  If it is, we start the actual
 * operation.
 *
 * @param cls closure with our configuration
 * @param result #GNUNET_YES if the namestore service is running
 */
static void
testservice_task (void *cls,
                  int result)
{
  const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  struct GNUNET_GNSRECORD_Data rd;

  if (GNUNET_YES != result)
  {
    FPRINTF (stderr, _("Service `%s' is not running\n"),
	     "namestore");
    return;
  }
  if (! (add|del|list|(NULL != nickstring)|(NULL != uri)|(NULL != reverse_pkey)) )
  {
    /* nothing more to be done */
    fprintf (stderr,
             _("No options given\n"));
    GNUNET_SCHEDULER_shutdown ();
    return;
  }
  GNUNET_CRYPTO_ecdsa_key_get_public (&zone_pkey,
                                    &pub);

  ns = GNUNET_NAMESTORE_connect (cfg);
  if (NULL == ns)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
                _("Failed to connect to namestore\n"));
    return;
  }
  if (add)
  {
    if (NULL == name)
    {
      fprintf (stderr,
               _("Missing option `%s' for operation `%s'\n"),
               "-n", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == typestring)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-t", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    type = GNUNET_GNSRECORD_typename_to_number (typestring);
    if (UINT32_MAX == type)
    {
      fprintf (stderr, _("Unsupported type `%s'\n"), typestring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == value)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-V", _("add"));
      ret = 1;
      GNUNET_SCHEDULER_shutdown ();
      return;
    }
    if (GNUNET_OK !=
	GNUNET_GNSRECORD_string_to_value (type,
					  value,
					  &data,
					  &data_size))
    {
      fprintf (stderr, _("Value `%s' invalid for record type `%s'\n"),
	       value,
	       typestring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (NULL == expirationstring)
    {
      fprintf (stderr,
	       _("Missing option `%s' for operation `%s'\n"),
	       "-e", _("add"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    if (0 == strcmp (expirationstring, "never"))
    {
      etime_abs = GNUNET_TIME_UNIT_FOREVER_ABS;
      etime_is_rel = GNUNET_NO;
    }
    else if (GNUNET_OK ==
             GNUNET_STRINGS_fancy_time_to_relative (expirationstring,
                                                    &etime_rel))
    {
      etime_is_rel = GNUNET_YES;
    }
    else if (GNUNET_OK ==
             GNUNET_STRINGS_fancy_time_to_absolute (expirationstring,
                                                    &etime_abs))
    {
      etime_is_rel = GNUNET_NO;
    }
    else
    {
      fprintf (stderr,
               _("Invalid time format `%s'\n"),
               expirationstring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    add_qe = GNUNET_NAMESTORE_records_lookup (ns, &zone_pkey, name,
        &get_existing_record, NULL );
  }
  if (del)
  {
    if (NULL == name)
    {
      fprintf (stderr,
               _("Missing option `%s' for operation `%s'\n"),
               "-n", _("del"));
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    del_qe = GNUNET_NAMESTORE_records_lookup (ns,
                                              &zone_pkey,
                                              name,
                                              &del_monitor,
                                              NULL);
  }
  if (list)
  {
    list_it = GNUNET_NAMESTORE_zone_iteration_start (ns,
                                                     &zone_pkey,
                                                     &display_record,
                                                     NULL);
  }
  if (NULL != reverse_pkey)
  {
    struct GNUNET_CRYPTO_EcdsaPublicKey pubkey;

    if (GNUNET_OK !=
        GNUNET_CRYPTO_ecdsa_public_key_from_string (reverse_pkey,
                                                       strlen (reverse_pkey),
                                                       &pubkey))
    {
      fprintf (stderr,
               _("Invalid public key for reverse lookup `%s'\n"),
               reverse_pkey);
      GNUNET_SCHEDULER_shutdown ();
    }
    reverse_qe = GNUNET_NAMESTORE_zone_to_name (ns,
                                                &zone_pkey,
                                                &pubkey,
                                                &handle_reverse_lookup,
                                                NULL);
  }
  if (NULL != uri)
  {
    char sh[105];
    char sname[64];
    struct GNUNET_CRYPTO_EcdsaPublicKey pkey;

    GNUNET_STRINGS_utf8_tolower (uri, uri);
    if ( (2 != (sscanf (uri,
                        "gnunet://gns/%52s/%63s",
                        sh,
                        sname)) ) ||
         (GNUNET_OK != GNUNET_CRYPTO_ecdsa_public_key_from_string (sh, strlen (sh), &pkey)) )
    {
      fprintf (stderr,
               _("Invalid URI `%s'\n"),
               uri);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    memset (&rd, 0, sizeof (rd));
    rd.data = &pkey;
    rd.data_size = sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey);
    rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY;
    if (GNUNET_YES == etime_is_rel)
    {
      rd.expiration_time = etime_rel.rel_value_us;
      rd.flags |= GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
    }
    else if (GNUNET_NO == etime_is_rel)
      rd.expiration_time = etime_abs.abs_value_us;
    else
      rd.expiration_time = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us;

    if (1 == is_shadow)
      rd.flags |= GNUNET_GNSRECORD_RF_SHADOW_RECORD;
    add_qe_uri = GNUNET_NAMESTORE_records_store (ns,
						 &zone_pkey,
						 sname,
						 1,
						 &rd,
						 &add_continuation,
						 &add_qe_uri);
  }
  if (NULL != nickstring)
  {
    if (0 == strlen(nickstring))
    {
      fprintf (stderr,
               _("Invalid nick `%s'\n"),
               nickstring);
      GNUNET_SCHEDULER_shutdown ();
      ret = 1;
      return;
    }
    add_qe_uri = GNUNET_NAMESTORE_set_nick(ns, &zone_pkey, nickstring,
        &add_continuation, &add_qe_uri);
  }
  if (monitor)
  {
    zm = GNUNET_NAMESTORE_zone_monitor_start (cfg,
					      &zone_pkey,
                                              GNUNET_YES,
					      &display_record,
					      &sync_cb,
					      NULL);
  }
}
Beispiel #16
0
static int
testNamespace (int i)
{
  char *uri;
  struct GNUNET_FS_Uri *ret;
  char *emsg;
  struct GNUNET_CRYPTO_EcdsaPrivateKey *ph;
  struct GNUNET_CRYPTO_EcdsaPublicKey id;
  char buf[1024];
  char ubuf[1024];
  char *sret;

  if (NULL !=
      (ret =
       GNUNET_FS_uri_parse ("gnunet://fs/sks/D1KJS9H2A82Q65VKQ0ML3RFU6U1D3VUK",
                            &emsg)))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  GNUNET_free (emsg);
  if (NULL !=
      (ret =
       GNUNET_FS_uri_parse
       ("gnunet://fs/sks/XQHH4R288W26EBV369F6RCE0PJVJTX2Y74Q2FJPMPGA31HJX2JG/this", &emsg)))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  GNUNET_free (emsg);
  if (NULL != (ret = GNUNET_FS_uri_parse ("gnunet://fs/sks/test", &emsg)))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  GNUNET_free (emsg);
  ph = GNUNET_CRYPTO_ecdsa_key_create ();
  GNUNET_CRYPTO_ecdsa_key_get_public (ph, &id);
  sret = GNUNET_STRINGS_data_to_string (&id, sizeof (id),
					ubuf, sizeof (ubuf) - 1);
  GNUNET_assert (NULL != sret);
  sret[0] = '\0';
  GNUNET_snprintf (buf, sizeof (buf),
		   "gnunet://fs/sks/%s/test",
		   ubuf);
  ret = GNUNET_FS_uri_parse (buf, &emsg);
  if (NULL == ret)
  {
    GNUNET_free (emsg);
    GNUNET_assert (0);
  }
  if (GNUNET_FS_uri_test_ksk (ret))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }
  if (!GNUNET_FS_uri_test_sks (ret))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_assert (0);
  }

  uri = GNUNET_FS_uri_to_string (ret);
  if (0 !=
      strcmp (uri,
              buf))
  {
    GNUNET_FS_uri_destroy (ret);
    GNUNET_free (uri);
    GNUNET_assert (0);
  }
  GNUNET_free (uri);
  GNUNET_FS_uri_destroy (ret);
  return 0;
}
Beispiel #17
0
/**
 * Function called from datastore with result from us looking for
 * a UBlock.  There are four cases:
 * 1) no result, means we move on to the next keyword
 * 2) UID is the same as the first UID, means we move on to next keyword
 * 3) UBlock for a different CHK, means we keep looking for more
 * 4) UBlock is for our CHK, means we remove the block and then move
 *           on to the next keyword
 *
 * @param cls the 'struct GNUNET_FS_UnindexContext *'
 * @param key key for the content
 * @param size number of bytes in data
 * @param data content stored
 * @param type type of the content
 * @param priority priority of the content
 * @param anonymity anonymity-level for the content
 * @param expiration expiration time for the content
 * @param uid unique identifier for the datum;
 *        maybe 0 if no unique identifier is available
 */
static void
process_kblock_for_unindex (void *cls,
			    const struct GNUNET_HashCode *key,
			    size_t size,
                            const void *data,
			    enum GNUNET_BLOCK_Type type,
			    uint32_t priority,
			    uint32_t anonymity,
			    struct GNUNET_TIME_Absolute expiration,
                            uint64_t uid)
{
  struct GNUNET_FS_UnindexContext *uc = cls;
  const struct UBlock *ub;
  struct GNUNET_FS_Uri *chk_uri;
  struct GNUNET_HashCode query;
  struct GNUNET_HashCode dh;

  uc->dqe = NULL;
  if (NULL == data)
  {
    /* no result */
    GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
    uc->ksk_offset++;
    GNUNET_FS_unindex_do_remove_kblocks_ (uc);
    return;
  }
  GNUNET_CRYPTO_hash (data,
                      size,
                      &dh);
  if (GNUNET_YES ==
      GNUNET_CONTAINER_multihashmap_contains (uc->seen_dh,
                                              &dh))
  {
    GNUNET_CONTAINER_multihashmap_clear (uc->seen_dh);
    uc->ksk_offset++;
    GNUNET_FS_unindex_do_remove_kblocks_ (uc);
    return;
  }
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CONTAINER_multihashmap_put (uc->seen_dh,
                                                    &dh,
                                                    uc,
                                                    GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
  GNUNET_assert (GNUNET_BLOCK_TYPE_FS_UBLOCK == type);
  if (size < sizeof (struct UBlock))
  {
    GNUNET_break (0);
    goto get_next;
  }
  ub = data;
  GNUNET_CRYPTO_hash (&ub->verification_key,
		      sizeof (ub->verification_key),
		      &query);
  if (0 != memcmp (&query,
                   key,
                   sizeof (struct GNUNET_HashCode)))
  {
    /* result does not match our keyword, skip */
    goto get_next;
  }
  {
    char pt[size - sizeof (struct UBlock)];
    struct GNUNET_CRYPTO_EcdsaPublicKey anon_pub;
    const char *keyword;

    GNUNET_CRYPTO_ecdsa_key_get_public (GNUNET_CRYPTO_ecdsa_key_get_anonymous (),
                                        &anon_pub);
    keyword = &uc->ksk_uri->data.ksk.keywords[uc->ksk_offset][1];
    GNUNET_FS_ublock_decrypt_ (&ub[1], size - sizeof (struct UBlock),
			       &anon_pub,
			       keyword,
			       pt);
    if (NULL == memchr (&pt[1], 0, sizeof (pt) - 1))
    {
      GNUNET_break_op (0); /* malformed UBlock */
      goto get_next;
    }
    chk_uri = GNUNET_FS_uri_parse (&pt[1], NULL);
    if (NULL == chk_uri)
    {
      GNUNET_break_op (0); /* malformed UBlock */
      goto get_next;
    }
  }
  if (0 != memcmp (&uc->chk,
		   &chk_uri->data.chk.chk,
		   sizeof (struct ContentHashKey)))
  {
    /* different CHK, ignore */
    GNUNET_FS_uri_destroy (chk_uri);
    goto get_next;
  }
  GNUNET_FS_uri_destroy (chk_uri);
  /* matches! */
  uc->dqe = GNUNET_DATASTORE_remove (uc->dsh,
				     key,
                                     size,
                                     data,
				     0 /* priority */,
                                     1 /* queue size */,
				     GNUNET_TIME_UNIT_FOREVER_REL,
				     &continue_after_remove,
				     uc);
  return;
 get_next:
  uc->dqe = GNUNET_DATASTORE_get_key (uc->dsh,
				      uc->roff++,
				      &uc->uquery,
				      GNUNET_BLOCK_TYPE_FS_UBLOCK,
				      0 /* priority */,
                                      1 /* queue size */,
				      GNUNET_TIME_UNIT_FOREVER_REL,
				      &process_kblock_for_unindex,
				      uc);
}
Beispiel #18
0
/**
 * Type of a function to call when we receive a message
 * from the service.
 *
 * @param cls closure
 * @param msg message received, NULL on timeout or fatal error
 */
static void
message_handler (void *cls,
		 const struct GNUNET_MessageHeader *msg)
{
  struct GNUNET_IDENTITY_Handle *h = cls;
  struct GNUNET_IDENTITY_Operation *op;
  struct GNUNET_IDENTITY_Ego *ego;
  const struct GNUNET_IDENTITY_ResultCodeMessage *rcm;
  const struct GNUNET_IDENTITY_UpdateMessage *um;
  const struct GNUNET_IDENTITY_SetDefaultMessage *sdm;
  struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  struct GNUNET_HashCode id;
  const char *str;
  uint16_t size;
  uint16_t name_len;

  if (NULL == msg)
  {
    reschedule_connect (h);
    return;
  }
  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Received message of type %d from identity service\n",
       ntohs (msg->type));
  size = ntohs (msg->size);
  switch (ntohs (msg->type))
  {
  case GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE:
    if (size < sizeof (struct GNUNET_IDENTITY_ResultCodeMessage))
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    rcm = (const struct GNUNET_IDENTITY_ResultCodeMessage *) msg;
    str = (const char *) &rcm[1];
    if ( (size > sizeof (struct GNUNET_IDENTITY_ResultCodeMessage)) &&
	 ('\0' != str[size - sizeof (struct GNUNET_IDENTITY_ResultCodeMessage) - 1]) )
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    if (size == sizeof (struct GNUNET_IDENTITY_ResultCodeMessage))
      str = NULL;

    op = h->op_head;
    GNUNET_CONTAINER_DLL_remove (h->op_head,
				 h->op_tail,
				 op);
    GNUNET_CLIENT_receive (h->client, &message_handler, h,
			   GNUNET_TIME_UNIT_FOREVER_REL);
    if (NULL != op->cont)
      op->cont (op->cls,
		str);
    else if (NULL != op->cb)
      op->cb (op->cls, NULL, NULL, NULL);
    GNUNET_free (op);
    break;
  case GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE:
    if (size < sizeof (struct GNUNET_IDENTITY_UpdateMessage))
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    um = (const struct GNUNET_IDENTITY_UpdateMessage *) msg;
    name_len = ntohs (um->name_len);

    str = (const char *) &um[1];
    if ( (size != name_len + sizeof (struct GNUNET_IDENTITY_UpdateMessage)) ||
	 ( (0 != name_len) &&
	   ('\0' != str[name_len - 1])) )
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    if (GNUNET_YES == ntohs (um->end_of_list))
    {
      /* end of initial list of data */
      GNUNET_CLIENT_receive (h->client, &message_handler, h,
			     GNUNET_TIME_UNIT_FOREVER_REL);
      if (NULL != h->cb)
	h->cb (h->cb_cls, NULL, NULL, NULL);
      break;
    }
    GNUNET_CRYPTO_ecdsa_key_get_public (&um->private_key,
				      &pub);
    GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
    if (0 == name_len)
      str = NULL;
    else
      str = (const char *) &um[1];
    ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
					     &id);
    if (NULL == ego)
    {
      /* ego was created */
      if (NULL == str)
      {
	/* deletion of unknown ego? not allowed */
	GNUNET_break (0);
	reschedule_connect (h);
	return;
      }
      ego = GNUNET_new (struct GNUNET_IDENTITY_Ego);
      ego->pk = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
      *ego->pk = um->private_key;
      ego->name = GNUNET_strdup (str);
      ego->id = id;
      GNUNET_assert (GNUNET_YES ==
		     GNUNET_CONTAINER_multihashmap_put (h->egos,
							&ego->id,
							ego,
							GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
    }
    if (NULL == str)
    {
      /* ego was deleted */
      GNUNET_assert (GNUNET_YES ==
		     GNUNET_CONTAINER_multihashmap_remove (h->egos,
							   &ego->id,
							   ego));
    }
    else
    {
      /* ego changed name */
      GNUNET_free (ego->name);
      ego->name = GNUNET_strdup (str);
    }
    GNUNET_CLIENT_receive (h->client, &message_handler, h,
			   GNUNET_TIME_UNIT_FOREVER_REL);
    /* inform application about change */
    if (NULL != h->cb)
      h->cb (h->cb_cls,
	     ego,
	     &ego->ctx,
	     str);
    if (NULL == str)
    {
      GNUNET_free (ego->pk);
      GNUNET_free (ego->name);
      GNUNET_free (ego);
    }
    break;
  case GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT:
    if (size < sizeof (struct GNUNET_IDENTITY_SetDefaultMessage))
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    sdm = (const struct GNUNET_IDENTITY_SetDefaultMessage *) msg;
    GNUNET_break (0 == ntohs (sdm->reserved));
    name_len = ntohs (sdm->name_len);
    str = (const char *) &sdm[1];
    if ( (size != name_len + sizeof (struct GNUNET_IDENTITY_SetDefaultMessage)) ||
	 ( (0 != name_len) &&
	   ('\0' != str[name_len - 1]) ) )
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    /* Note: we know which service this should be for, so we're not
       really using 'str' henceforth */
    GNUNET_CRYPTO_ecdsa_key_get_public (&sdm->private_key,
				      &pub);
    GNUNET_CRYPTO_hash (&pub, sizeof (pub), &id);
    ego = GNUNET_CONTAINER_multihashmap_get (h->egos,
					     &id);
    if (NULL == ego)
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    op = h->op_head;
    if (NULL == op)
    {
      GNUNET_break (0);
      reschedule_connect (h);
      return;
    }
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Received SET_DEFAULT message from identity service\n");
    GNUNET_CONTAINER_DLL_remove (h->op_head,
				 h->op_tail,
				 op);
    GNUNET_CLIENT_receive (h->client, &message_handler, h,
			   GNUNET_TIME_UNIT_FOREVER_REL);
    if (NULL != op->cb)
      op->cb (op->cls,
	      ego,
	      &ego->ctx,
	      ego->name);
    GNUNET_free (op);
    break;
  default:
    GNUNET_break (0);
    reschedule_connect (h);
    return;
  }
}
Beispiel #19
0
/**
 * Sign name and records
 *
 * @param key the private key
 * @param expire block expiration
 * @param label the name for the records
 * @param rd record data
 * @param rd_count number of records
 * @return NULL on error (block too large)
 */
struct GNUNET_GNSRECORD_Block *
GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
			       struct GNUNET_TIME_Absolute expire,
			       const char *label,
			       const struct GNUNET_GNSRECORD_Data *rd,
			       unsigned int rd_count)
{
  size_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count, rd);
  char payload[sizeof (uint32_t) + payload_len];
  struct GNUNET_GNSRECORD_Block *block;
  struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
  struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey;
  struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  struct GNUNET_CRYPTO_SymmetricSessionKey skey;
  struct GNUNET_GNSRECORD_Data rdc[rd_count];
  uint32_t rd_count_nbo;
  unsigned int i;
  struct GNUNET_TIME_Absolute now;

  if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE)
    return NULL;
  /* convert relative to absolute times */
  now = GNUNET_TIME_absolute_get ();
  for (i=0;i<rd_count;i++)
  {
    rdc[i] = rd[i];
    if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
    {
      struct GNUNET_TIME_Relative t;

      /* encrypted blocks must never have relative expiration times, convert! */
      rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
      t.rel_value_us = rdc[i].expiration_time;
      rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us;
    }
  }
  /* serialize */
  rd_count_nbo = htonl (rd_count);
  memcpy (payload, &rd_count_nbo, sizeof (uint32_t));
  GNUNET_assert (payload_len ==
		 GNUNET_GNSRECORD_records_serialize (rd_count, rdc,
						     payload_len, &payload[sizeof (uint32_t)]));
  block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) +
			 sizeof (uint32_t) + payload_len);
  block->purpose.size = htonl (sizeof (uint32_t) + payload_len +
			       sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
			       sizeof (struct GNUNET_TIME_AbsoluteNBO));
  block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
  block->expiration_time = GNUNET_TIME_absolute_hton (expire);
  /* encrypt and sign */
  dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key,
                                                 label,
                                                 "gns");
  GNUNET_CRYPTO_ecdsa_key_get_public (dkey,
				    &block->derived_key);
  GNUNET_CRYPTO_ecdsa_key_get_public (key,
				    &pkey);
  derive_block_aes_key (&iv, &skey, label, &pkey);
  GNUNET_break (payload_len + sizeof (uint32_t) ==
		GNUNET_CRYPTO_symmetric_encrypt (payload, payload_len + sizeof (uint32_t),
                                                 &skey, &iv,
                                                 &block[1]));
  if (GNUNET_OK !=
      GNUNET_CRYPTO_ecdsa_sign (dkey,
			      &block->purpose,
			      &block->signature))
  {
    GNUNET_break (0);
    GNUNET_free (dkey);
    GNUNET_free (block);
    return NULL;
  }
  GNUNET_free (dkey);
  return block;
}
Beispiel #20
0
static void
run (void *cls, char *const *args, const char *cfgfile,
     const struct GNUNET_CONFIGURATION_Handle *cfg)
{
  struct GNUNET_PSYCSTORE_PluginFunctions *db;

  ok = 1;
  db = load_plugin (cfg);
  if (NULL == db)
  {
    FPRINTF (stderr,
             "%s",
	     "Failed to initialize PSYCstore.  "
             "Database likely not setup, skipping test.\n");
    ok = 77;
    return;
  }

  /* Store & test membership */

  LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n");

  channel_key = GNUNET_CRYPTO_eddsa_key_create ();
  slave_key = GNUNET_CRYPTO_ecdsa_key_create ();

  GNUNET_CRYPTO_eddsa_key_get_public (channel_key,
                                                  &channel_pub_key);
  GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key);

  LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n");

  GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key,
                                                    &slave_pub_key, GNUNET_YES,
                                                    4, 2, 1));

  LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n");

  GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
                                                    &slave_pub_key, 4));

  GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key,
                                                    &slave_pub_key, 2));

  GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key,
                                                   &slave_pub_key, 1));

  /* Store & get messages */

  LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n");

  struct GNUNET_MULTICAST_MessageHeader *msg
    = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key));
  GNUNET_assert (msg != NULL);

  msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE);
  msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key));

  uint64_t fragment_id = INT64_MAX - 1;
  msg->fragment_id = GNUNET_htonll (fragment_id);

  uint64_t message_id = INT64_MAX - 10;
  msg->message_id = GNUNET_htonll (message_id);

  uint64_t group_generation = INT64_MAX - 3;
  msg->group_generation = GNUNET_htonll (group_generation);

  msg->hop_counter = htonl (9);
  msg->fragment_offset = GNUNET_htonll (0);
  msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT);

  GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key));

  msg->purpose.size = htonl (ntohs (msg->header.size)
                             - sizeof (msg->header)
                             - sizeof (msg->hop_counter)
                             - sizeof (msg->signature));
  msg->purpose.purpose = htonl (234);
  GNUNET_assert (GNUNET_OK ==
                 GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature));

  LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");

  struct FragmentClosure fcls = { 0 };
  fcls.n = 0;
  fcls.msg[0] = msg;
  fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE;

  GNUNET_assert (
    GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg,
                                     fcls.flags[0]));

  LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);

  uint64_t ret_frags = 0;
  GNUNET_assert (
    GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
                                   fragment_id, fragment_id,
                                   &ret_frags, fragment_cb, &fcls));
  GNUNET_assert (fcls.n == 1);

  LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n");

  fcls.n = 0;
  GNUNET_assert (
    GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key,
                                           GNUNET_ntohll (msg->message_id),
                                           GNUNET_ntohll (msg->fragment_offset),
                                           fragment_cb, &fcls));
  GNUNET_assert (fcls.n == 1);

  LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n");
  GNUNET_assert (
    GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key,
                                        GNUNET_ntohll (msg->message_id),
                                        GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED));
  LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id);

  fcls.n = 0;
  fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED;

  GNUNET_assert (
    GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key,
                                   fragment_id, fragment_id,
                                   &ret_frags, fragment_cb, &fcls));

  GNUNET_assert (fcls.n == 1);

  LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n");

  struct GNUNET_MULTICAST_MessageHeader *msg1
    = GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key));

  GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key));

  msg1->fragment_id = GNUNET_htonll (INT64_MAX);
  msg1->fragment_offset = GNUNET_htonll (32768);

  fcls.n = 0;
  fcls.msg[1] = msg1;
  fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH;

  GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1,
                                                  fcls.flags[1]));

  LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n");

  GNUNET_assert (
    GNUNET_OK == db->message_get (db->cls, &channel_pub_key,
                                  message_id, message_id, 0,
                                  &ret_frags, fragment_cb, &fcls));
  GNUNET_assert (fcls.n == 2 && ret_frags == 2);

  /* Message counters */

  LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n");

  fragment_id = 0;
  message_id = 0;
  group_generation = 0;
  GNUNET_assert (
    GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key,
                                           &fragment_id, &message_id,
                                           &group_generation)
    && fragment_id == GNUNET_ntohll (msg1->fragment_id)
    && message_id == GNUNET_ntohll (msg1->message_id)
    && group_generation == GNUNET_ntohll (msg1->group_generation));

  /* Modify state */

  LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n");

  LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");

  message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1;
  GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
                                                      message_id, 0));

  GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
                                                   GNUNET_PSYC_OP_ASSIGN,
                                                   "_foo",
                                                   C2ARG("one two three")));

  GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
                                                   GNUNET_PSYC_OP_ASSIGN,
                                                   "_foo_bar", slave_key,
                                                   sizeof (*slave_key)));

  GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
                                                    message_id));

  LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n");

  struct StateClosure scls = { 0 };
  scls.n = 0;
  scls.value[0] = "one two three";
  scls.value_size[0] = strlen ("one two three");

  GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo",
                                             state_cb, &scls));
  GNUNET_assert (scls.n == 1);

  LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n");

  scls.n = 0;
  scls.value[1] = slave_key;
  scls.value_size[1] = sizeof (*slave_key);

  GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
                                                    "_foo", state_cb, &scls));
  GNUNET_assert (scls.n == 2);

  LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");

  scls.n = 0;
  GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key,
                                                    state_cb, &scls));
  GNUNET_assert (scls.n == 0);

  LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n");

  GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls,
                                                       &channel_pub_key));

  LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n");

  scls.n = 0;
  GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key,
                                                     state_cb, &scls));
  GNUNET_assert (scls.n == 2);

  /* State counters */

  LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n");

  uint64_t max_state_msg_id = 0;
  GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key,
                                                      &max_state_msg_id)
                 && max_state_msg_id == message_id);

  /* State sync */

  LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n");

  scls.n = 0;
  scls.value[0] = channel_key;
  scls.value_size[0] = sizeof (*channel_key);
  scls.value[1] = "three two one";
  scls.value_size[1] = strlen ("three two one");

  GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key));

  GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
                                                     "_sync_bar", scls.value[0],
                                                     scls.value_size[0]));

  GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key,
                                                     "_sync_foo", scls.value[1],
                                                     scls.value_size[1]));

  GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key,
                                                  max_state_msg_id,
                                                  INT64_MAX - 5));

  GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key,
                                                    "_foo", state_cb, &scls));
  GNUNET_assert (scls.n == 0);

  GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key,
                                                    "_sync", state_cb, &scls));
  GNUNET_assert (scls.n == 2);

  scls.n = 0;
  GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key,
                                                    state_cb, &scls));
  GNUNET_assert (scls.n == 2);

  /* Modify state after sync */

  LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n");

  message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6;
  GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key,
                                                      message_id,
                                                      message_id - max_state_msg_id));

  GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key,
                                                   GNUNET_PSYC_OP_ASSIGN,
                                                   "_sync_foo",
                                                   C2ARG("five six seven")));

  GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key,
                                                    message_id));

  /* Reset state */

  LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n");

  scls.n = 0;
  GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key));
  GNUNET_assert (scls.n == 0);

  ok = 0;

  if (NULL != channel_key)
  {
    GNUNET_free (channel_key);
    channel_key = NULL;
  }
  if (NULL != slave_key)
  {
    GNUNET_free (slave_key);
    slave_key = NULL;
  }

  unload_plugin (db);
}