From: Christian Grothoff Date: Mon, 5 Apr 2010 13:07:27 +0000 (+0000) Subject: nblock support done X-Git-Tag: initial-import-from-subversion-38251~22280 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=acd08b65a860450488d5e6b5403e43bed3748dc9;p=oweals%2Fgnunet.git nblock support done --- diff --git a/src/fs/fs.h b/src/fs/fs.h index 3a42fee2d..a9a585a15 100644 --- a/src/fs/fs.h +++ b/src/fs/fs.h @@ -1217,21 +1217,38 @@ struct SBlock 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 */ diff --git a/src/fs/fs_namespace.c b/src/fs/fs_namespace.c index 873494c4f..96e1f4f3f 100644 --- a/src/fs/fs_namespace.c +++ b/src/fs/fs_namespace.c @@ -79,9 +79,49 @@ struct AdvertisementContext 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; }; @@ -99,14 +139,74 @@ advertisement_cont (void *cls, 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); } @@ -114,6 +214,7 @@ advertisement_cont (void *cls, * 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 @@ -125,6 +226,7 @@ advertisement_cont (void *cls, */ 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, @@ -138,10 +240,10 @@ GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, 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); @@ -157,11 +259,10 @@ GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, 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, @@ -169,46 +270,42 @@ GNUNET_FS_namespace_advertise (struct GNUNET_FS_Handle *h, 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); } diff --git a/src/fs/fs_search.c b/src/fs/fs_search.c index ce4af43fc..8674f824c 100644 --- a/src/fs/fs_search.c +++ b/src/fs/fs_search.c @@ -24,9 +24,6 @@ * @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) @@ -411,6 +408,88 @@ process_kblock (struct GNUNET_FS_SearchContext *sc, } +/** + * 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;iuri->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. * @@ -535,7 +614,17 @@ process_result (struct GNUNET_FS_SearchContext *sc, 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: @@ -640,7 +729,7 @@ transmit_search_request (void *cls, { 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; } diff --git a/src/fs/gnunet-pseudonym.c b/src/fs/gnunet-pseudonym.c index e7b2bb8dd..93b51817d 100644 --- a/src/fs/gnunet-pseudonym.c +++ b/src/fs/gnunet-pseudonym.c @@ -251,7 +251,6 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c) { - struct GNUNET_FS_Uri *ns_uri; struct GNUNET_TIME_Absolute expiration; char *emsg; @@ -289,9 +288,6 @@ run (void *cls, { 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) { @@ -299,17 +295,16 @@ run (void *cls, 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; } } diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c index 22e826536..13f1c727c 100644 --- a/src/fs/gnunet-service-fs.c +++ b/src/fs/gnunet-service-fs.c @@ -1640,6 +1640,64 @@ check_kblock (const struct KBlock *kb, } +/** + * 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. * @@ -1855,6 +1913,7 @@ process_reply (void *cls, } /* then: fall-through! */ case GNUNET_DATASTORE_BLOCKTYPE_KBLOCK: + case GNUNET_DATASTORE_BLOCKTYPE_NBLOCK: if (pr->bf != NULL) { mingle_hash (&chash, pr->mingle, &mhash); @@ -1897,9 +1956,6 @@ process_reply (void *cls, 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; @@ -2054,8 +2110,11 @@ handle_p2p_put (void *cls, 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 */ @@ -2744,10 +2803,12 @@ handle_start_search (void *cls, #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); @@ -2757,7 +2818,9 @@ handle_start_search (void *cls, } /* 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) && diff --git a/src/include/gnunet_fs_service.h b/src/include/gnunet_fs_service.h index e26d6b000..f24b3d8b7 100644 --- a/src/include/gnunet_fs_service.h +++ b/src/include/gnunet_fs_service.h @@ -2053,6 +2053,7 @@ GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc); * 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 @@ -2064,6 +2065,7 @@ GNUNET_FS_unindex_stop (struct GNUNET_FS_UnindexContext *uc); */ 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, diff --git a/src/include/gnunet_signatures.h b/src/include/gnunet_signatures.h index 8b71bb616..29da16b42 100644 --- a/src/include/gnunet_signatures.h +++ b/src/include/gnunet_signatures.h @@ -81,10 +81,15 @@ extern "C" */ #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 */