struct NBlock
{
+ /**
+ * GNUNET_RSA_Signature using RSA-key generated from search keyword.
+ */
+ struct GNUNET_CRYPTO_RsaSignature ksk_signature;
+
+ /**
+ * What is being signed and why?
+ */
+ struct GNUNET_CRYPTO_RsaSignaturePurpose ksk_purpose;
+
+ /**
+ * Key generated (!) from the H(keyword) as the seed!
+ */
+ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded keyspace;
+
/**
* GNUNET_RSA_Signature using RSA-key of the namespace
*/
- struct GNUNET_CRYPTO_RsaSignature signature;
+ struct GNUNET_CRYPTO_RsaSignature ns_signature;
/**
* What is being signed and why?
*/
- struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
+ struct GNUNET_CRYPTO_RsaSignaturePurpose ns_purpose;
/**
* Public key of the namespace.
*/
struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded subspace;
+ /* from here on, data is encrypted with H(keyword) */
+
/* 0-terminated root identifier here */
/* variable-size Meta-Data follows here */
struct GNUNET_DATASTORE_Handle *dsh;
/**
- * URI that was created.
+ * Our KSK URI.
*/
- struct GNUNET_FS_Uri *uri;
+ struct GNUNET_FS_Uri *ksk_uri;
+
+ /**
+ * Plaintext.
+ */
+ char *pt;
+
+ /**
+ * NBlock to sign and store.
+ */
+ struct NBlock *nb;
+
+ /**
+ * The namespace.
+ */
+ struct GNUNET_FS_Namespace *ns;
+
+ /**
+ * Expiration time.
+ */
+ struct GNUNET_TIME_Absolute expiration;
+
+ /**
+ * Number of bytes of plaintext.
+ */
+ size_t pt_size;
+
+ /**
+ * Anonymity level.
+ */
+ uint32_t anonymity;
+
+ /**
+ * Content priority.
+ */
+ uint32_t priority;
+
+ /**
+ * Current keyword offset.
+ */
+ unsigned int pos;
};
const char *msg)
{
struct AdvertisementContext *ac = cls;
+ const char *keyword;
+ GNUNET_HashCode key;
+ GNUNET_HashCode query;
+ struct GNUNET_CRYPTO_AesSessionKey skey;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
+ struct GNUNET_CRYPTO_RsaPrivateKey *pk;
if (GNUNET_OK != success)
- ac->cont (ac->cont_cls, NULL, msg);
- else
- ac->cont (ac->cont_cls, ac->uri, NULL);
- GNUNET_DATASTORE_disconnect (ac->dsh, GNUNET_NO);
- GNUNET_FS_uri_destroy (ac->uri);
- GNUNET_free (ac);
+ {
+ /* error! */
+ GNUNET_DATASTORE_disconnect (ac->dsh, GNUNET_NO);
+ ac->cont (ac->cont_cls, NULL, msg);
+ GNUNET_FS_uri_destroy (ac->ksk_uri);
+ GNUNET_free (ac->pt);
+ GNUNET_free (ac->nb);
+ GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
+ GNUNET_free (ac);
+ return;
+ }
+ if (ac->pos == ac->ksk_uri->data.ksk.keywordCount)
+ {
+ /* done! */
+ GNUNET_DATASTORE_disconnect (ac->dsh, GNUNET_NO);
+ ac->cont (ac->cont_cls, ac->ksk_uri, NULL);
+ GNUNET_FS_uri_destroy (ac->ksk_uri);
+ GNUNET_free (ac->pt);
+ GNUNET_free (ac->nb);
+ GNUNET_FS_namespace_delete (ac->ns, GNUNET_NO);
+ GNUNET_free (ac);
+ return;
+ }
+
+ keyword = ac->ksk_uri->data.ksk.keywords[ac->pos++];
+ /* first character of keyword indicates if it is
+ mandatory or not -- ignore for hashing */
+ GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
+ GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
+ GNUNET_CRYPTO_aes_encrypt (ac->pt,
+ ac->pt_size,
+ &skey,
+ &iv,
+ &ac->nb[1]);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (ac->ns->key,
+ &ac->nb->ns_purpose,
+ &ac->nb->ns_signature));
+ pk = GNUNET_CRYPTO_rsa_key_create_from_hash (&key);
+ GNUNET_CRYPTO_rsa_key_get_public (pk, &ac->nb->keyspace);
+ GNUNET_CRYPTO_hash (&ac->nb->keyspace,
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &query);
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (pk,
+ &ac->nb->ksk_purpose,
+ &ac->nb->ksk_signature));
+ GNUNET_CRYPTO_rsa_key_free (pk);
+ GNUNET_DATASTORE_put (ac->dsh,
+ 0 /* no reservation */,
+ &query,
+ ac->pt_size + sizeof (struct NBlock),
+ ac->nb,
+ GNUNET_DATASTORE_BLOCKTYPE_NBLOCK,
+ ac->priority,
+ ac->anonymity,
+ ac->expiration,
+ GNUNET_CONSTANTS_SERVICE_TIMEOUT,
+ &advertisement_cont,
+ ac);
}
* Publish an advertismement for a namespace.
*
* @param h handle to the file sharing subsystem
+ * @param ksk_uri keywords to use for advertisment
* @param namespace handle for the namespace that should be advertised
* @param meta meta-data for the namespace advertisement
* @param anonymity for the namespace advertismement
*/
void
GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h,
+ struct GNUNET_FS_Uri *ksk_uri,
struct GNUNET_FS_Namespace *namespace,
const struct GNUNET_CONTAINER_MetaData *meta,
uint32_t anonymity,
size_t size;
ssize_t mdsize;
struct NBlock *nb;
- char *rtgt;
char *mdst;
struct GNUNET_DATASTORE_Handle *dsh;
struct AdvertisementContext *ctx;
+ char *pt;
/* create advertisements */
mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
size = MAX_NBLOCK_SIZE;
mdsize = size - sizeof (struct NBlock) - reslen;
}
- nb = GNUNET_malloc (size);
- GNUNET_CRYPTO_rsa_key_get_public (namespace->key, &nb->subspace);
- rtgt = (char *) &nb[1];
- memcpy (rtgt, rootEntry, reslen);
- mdst = &rtgt[reslen];
+
+ pt = GNUNET_malloc (mdsize + reslen);
+ memcpy (pt, rootEntry, reslen);
+ mdst = &pt[reslen];
mdsize = GNUNET_CONTAINER_meta_data_serialize (meta,
&mdst,
mdsize,
if (mdsize == -1)
{
GNUNET_break (0);
- GNUNET_free (nb);
+ GNUNET_free (pt);
cont (cont_cls, NULL, _("Failed to serialize meta data"));
return;
}
- size = mdsize + sizeof (struct NBlock) + reslen;
- nb->purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature));
- nb->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK);
- GNUNET_break (GNUNET_OK ==
- GNUNET_CRYPTO_rsa_sign (namespace->key,
- &nb->purpose,
- &nb->signature));
+ size = mdsize + sizeof (struct NBlock) + reslen;
+ nb = GNUNET_malloc (size);
+ GNUNET_CRYPTO_rsa_key_get_public (namespace->key,
+ &nb->subspace);
+ nb->ns_purpose.size = htonl (mdsize + reslen +
+ sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
+ nb->ns_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK);
+ nb->ksk_purpose.size = htonl (size - sizeof (struct GNUNET_CRYPTO_RsaSignature));
+ nb->ksk_purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG);
dsh = GNUNET_DATASTORE_connect (h->cfg, h->sched);
if (NULL == dsh)
{
GNUNET_free (nb);
+ GNUNET_free (pt);
cont (cont_cls, NULL, _("Failed to connect to datastore service"));
return;
- }
+ }
ctx = GNUNET_malloc (sizeof (struct AdvertisementContext));
ctx->cont = cont;
ctx->cont_cls = cont_cls;
ctx->dsh = dsh;
- ctx->uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
- ctx->uri->type = sks;
- ctx->uri->data.sks.identifier = GNUNET_strdup ("");
- GNUNET_CRYPTO_hash (&nb->subspace,
- sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
- &ctx->uri->data.sks.namespace);
- GNUNET_DATASTORE_put (dsh,
- 0,
- &ctx->uri->data.sks.namespace,
- size,
- nb,
- GNUNET_DATASTORE_BLOCKTYPE_NBLOCK,
- priority,
- anonymity,
- expiration,
- GNUNET_CONSTANTS_SERVICE_TIMEOUT,
- &advertisement_cont,
- ctx);
+ ctx->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
+ ctx->nb = nb;
+ ctx->pt = pt;
+ ctx->pt_size = mdsize + reslen;
+ ctx->ns = namespace;
+ ctx->ns->rc++;
+ ctx->anonymity = anonymity;
+ ctx->priority = priority;
+ ctx->expiration = expiration;
+ advertisement_cont (ctx, GNUNET_OK, NULL);
}
* @author Christian Grothoff
*
* TODO:
- * - handle namespace advertisements (NBlocks, see FIXME;
- * note that we currently use KBLOCK instead of ANY when
- * searching => NBLOCKS would not fit! FIX this as well!)
* - add support for pushing "already seen" information
* to FS service for bloomfilter (can wait)
* - handle availability probes (can wait)
}
+/**
+ * Process a keyword-search result with a namespace advertisment.
+ *
+ * @param sc our search context
+ * @param nb the nblock
+ * @param size size of nb
+ */
+static void
+process_nblock (struct GNUNET_FS_SearchContext *sc,
+ const struct NBlock *nb,
+ size_t size)
+{
+ unsigned int i;
+ size_t j;
+ GNUNET_HashCode q;
+ char pt[size - sizeof (struct NBlock)];
+ struct GNUNET_CRYPTO_AesSessionKey skey;
+ struct GNUNET_CRYPTO_AesInitializationVector iv;
+ const char *eos;
+ struct GNUNET_CONTAINER_MetaData *meta;
+ struct GNUNET_FS_Uri *uri;
+
+ GNUNET_CRYPTO_hash (&nb->keyspace,
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &q);
+ /* find key */
+ for (i=0;i<sc->uri->data.ksk.keywordCount;i++)
+ if (0 == memcmp (&q,
+ &sc->requests[i].query,
+ sizeof (GNUNET_HashCode)))
+ break;
+ if (i == sc->uri->data.ksk.keywordCount)
+ {
+ /* oops, does not match any of our keywords!? */
+ GNUNET_break (0);
+ return;
+ }
+ /* decrypt */
+ GNUNET_CRYPTO_hash_to_aes_key (&sc->requests[i].key, &skey, &iv);
+ GNUNET_CRYPTO_aes_decrypt (&nb[1],
+ size - sizeof (struct NBlock),
+ &skey,
+ &iv,
+ pt);
+ /* parse */
+ eos = memchr (pt, 0, sizeof (pt));
+ if (NULL == eos)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ j = eos - pt + 1;
+ if (sizeof (pt) == j)
+ meta = GNUNET_CONTAINER_meta_data_create ();
+ else
+ meta = GNUNET_CONTAINER_meta_data_deserialize (&pt[j],
+ sizeof (pt) - j);
+ if (meta == NULL)
+ {
+ GNUNET_break_op (0); /* nblock malformed */
+ return;
+ }
+
+ uri = GNUNET_malloc (sizeof (struct GNUNET_FS_Uri));
+ uri->type = sks;
+ uri->data.sks.identifier = GNUNET_strdup (pt);
+ GNUNET_CRYPTO_hash (&nb->subspace,
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &uri->data.sks.namespace);
+ /* FIXME: should store 'root' in meta? */
+ GNUNET_PSEUDONYM_add (sc->h->cfg,
+ &uri->data.sks.namespace,
+ meta);
+ /* process */
+ process_ksk_result (sc, &sc->requests[i], uri, meta);
+
+ /* clean up */
+ GNUNET_CONTAINER_meta_data_destroy (meta);
+ GNUNET_FS_uri_destroy (uri);
+}
+
+
/**
* Process a namespace-search result.
*
process_sblock (sc, data, size);
break;
case GNUNET_DATASTORE_BLOCKTYPE_NBLOCK:
- GNUNET_break (0); // FIXME: not implemented!
+ if (! GNUNET_FS_uri_test_ksk (sc->uri))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (sizeof (struct NBlock) > size)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ process_nblock (sc, data, size);
break;
case GNUNET_DATASTORE_BLOCKTYPE_ANY:
case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
{
sm[i].header.size = htons (sizeof (struct SearchMessage));
sm[i].header.type = htons (GNUNET_MESSAGE_TYPE_FS_START_SEARCH);
- sm[i].type = htonl (GNUNET_DATASTORE_BLOCKTYPE_KBLOCK);
+ sm[i].type = htonl (GNUNET_DATASTORE_BLOCKTYPE_ANY);
sm[i].anonymity_level = htonl (sc->anonymity);
sm[i].query = sc->requests[i].query;
}
const char *cfgfile,
const struct GNUNET_CONFIGURATION_Handle *c)
{
- struct GNUNET_FS_Uri *ns_uri;
struct GNUNET_TIME_Absolute expiration;
char *emsg;
{
if (NULL != root_identifier)
{
- emsg = NULL;
- ns_uri = GNUNET_FS_uri_sks_create (ns, root_identifier, &emsg);
- GNUNET_assert (emsg == NULL);
expiration = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_YEARS);
if (ksk_uri == NULL)
{
ksk_uri = GNUNET_FS_uri_parse ("gnunet://fs/ksk/namespace", &emsg);
GNUNET_assert (NULL == emsg);
}
- GNUNET_FS_publish_ksk (h,
- ksk_uri,
- adv_metadata,
- ns_uri,
- expiration,
- anonymity,
- priority,
- GNUNET_FS_PUBLISH_OPTION_NONE,
- &post_advertising,
- NULL);
- GNUNET_FS_uri_destroy (ns_uri);
+ GNUNET_FS_namespace_advertise (h,
+ ksk_uri,
+ ns,
+ adv_metadata,
+ anonymity,
+ priority,
+ expiration,
+ root_identifier,
+ &post_advertising,
+ NULL);
return;
}
}
}
+/**
+ * Check if the given NBlock is well-formed.
+ *
+ * @param nb the nblock data (or at least "dsize" bytes claiming to be one)
+ * @param dsize size of "nb" in bytes; check for < sizeof(struct NBlock)!
+ * @param query where to store the query that this block answers
+ * @return GNUNET_OK if this is actually a well-formed NBlock
+ */
+static int
+check_nblock (const struct NBlock *nb,
+ size_t dsize,
+ GNUNET_HashCode *query)
+{
+ if (dsize < sizeof (struct NBlock))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (dsize - sizeof (struct NBlock) !=
+ ntohl (nb->ns_purpose.size)
+ - sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)
+ - sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (dsize !=
+ ntohl (nb->ksk_purpose.size) + sizeof (struct GNUNET_CRYPTO_RsaSignature))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG,
+ &nb->ksk_purpose,
+ &nb->ksk_signature,
+ &nb->keyspace))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK,
+ &nb->ns_purpose,
+ &nb->ns_signature,
+ &nb->subspace))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (query != NULL)
+ GNUNET_CRYPTO_hash (&nb->keyspace,
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ query);
+ return GNUNET_OK;
+}
+
+
/**
* Check if the given SBlock is well-formed.
*
}
/* then: fall-through! */
case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK:
+ case GNUNET_DATASTORE_BLOCKTYPE_NBLOCK:
if (pr->bf != NULL)
{
mingle_hash (&chash, pr->mingle, &mhash);
pr->replies_seen[pr->replies_seen_off++] = chash;
}
break;
- case GNUNET_DATASTORE_BLOCKTYPE_NBLOCK:
- // FIXME: any checks against duplicates for NBlocks?
- break;
default:
GNUNET_break (0);
return GNUNET_YES;
return GNUNET_SYSERR;
break;
case GNUNET_DATASTORE_BLOCKTYPE_NBLOCK:
- // FIXME -- validate NBLOCK!
- GNUNET_break (0);
+ if (GNUNET_OK !=
+ check_nblock ((const struct NBlock*) &put[1],
+ dsize,
+ &query))
+ return GNUNET_SYSERR;
return GNUNET_OK;
default:
/* unknown block type */
#endif
switch (type)
{
+ case GNUNET_DATASTORE_BLOCKTYPE_ANY:
case GNUNET_DATASTORE_BLOCKTYPE_DBLOCK:
case GNUNET_DATASTORE_BLOCKTYPE_IBLOCK:
case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK:
case GNUNET_DATASTORE_BLOCKTYPE_SBLOCK:
+ case GNUNET_DATASTORE_BLOCKTYPE_NBLOCK:
break;
default:
GNUNET_break (0);
}
/* detect duplicate KBLOCK requests */
- if (type == GNUNET_DATASTORE_BLOCKTYPE_KBLOCK)
+ if ( (type == GNUNET_DATASTORE_BLOCKTYPE_KBLOCK) ||
+ (type == GNUNET_DATASTORE_BLOCKTYPE_NBLOCK) ||
+ (type == GNUNET_DATASTORE_BLOCKTYPE_ANY) )
{
crl = cl->rl_head;
while ( (crl != NULL) &&
* Publish an advertismement for a namespace.
*
* @param h handle to the file sharing subsystem
+ * @param ksk_uri keywords to use for advertisment
* @param namespace handle for the namespace that should be advertised
* @param meta meta-data for the namespace advertisement
* @param anonymity for the namespace advertismement
*/
void
GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h,
+ struct GNUNET_FS_Uri *ksk_uri,
struct GNUNET_FS_Namespace *namespace,
const struct GNUNET_CONTAINER_MetaData *meta,
uint32_t anonymity,
*/
#define GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK 7
+/**
+ * Keyword-based signature of advertisment for a namespace.
+ */
+#define GNUNET_SIGNATURE_PURPOSE_FS_NBLOCK_KSIG 8
+
/**
*
*/
-#define GNUNET_SIGNATURE_PURPOSE_RESOLVER_RESPONSE 8
+#define GNUNET_SIGNATURE_PURPOSE_RESOLVER_RESPONSE 9
#if 0 /* keep Emacsens' auto-indent happy */