2 This file is part of GNUnet.
3 (C) 2009, 2010, 2012, 2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file fs/fs_publish_ksk.c
23 * @brief publish a URI under a keyword in GNUnet
24 * @see https://gnunet.org/encoding and #2564
25 * @author Krista Bennett
26 * @author Christian Grothoff
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_fs_service.h"
39 * Context for the KSK publication.
41 struct GNUNET_FS_PublishKskContext
47 struct GNUNET_FS_Uri *ksk_uri;
52 struct GNUNET_FS_Handle *h;
55 * The master block that we are sending
56 * (in plaintext), has "mdsize+slen" more
57 * bytes than the struct would suggest.
62 * Buffer of the same size as "kb" for
63 * the encrypted version.
68 * Handle to the datastore, NULL if we are just
71 struct GNUNET_DATASTORE_Handle *dsh;
74 * Handle to datastore PUT request.
76 struct GNUNET_DATASTORE_QueueEntry *qre;
81 GNUNET_SCHEDULER_TaskIdentifier ksk_task;
84 * Function to call once we're done.
86 GNUNET_FS_PublishContinuation cont;
94 * When should the KBlocks expire?
96 struct GNUNET_FS_BlockOptions bo;
99 * Size of the serialized metadata.
104 * Size of the (CHK) URI as a string.
109 * Keyword that we are currently processing.
117 * Continuation of "GNUNET_FS_publish_ksk" that performs
118 * the actual publishing operation (iterating over all
121 * @param cls closure of type "struct PublishKskContext*"
125 publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
129 * Function called by the datastore API with
130 * the result from the PUT request.
132 * @param cls closure of type "struct GNUNET_FS_PublishKskContext*"
133 * @param success GNUNET_OK on success
134 * @param min_expiration minimum expiration time required for content to be stored
135 * @param msg error message (or NULL)
138 kb_put_cont (void *cls, int success,
139 struct GNUNET_TIME_Absolute min_expiration,
142 struct GNUNET_FS_PublishKskContext *pkc = cls;
145 if (GNUNET_OK != success)
147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148 "KBlock PUT operation failed: %s\n", msg);
149 pkc->cont (pkc->cont_cls, NULL, msg);
150 GNUNET_FS_publish_ksk_cancel (pkc);
153 pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
158 * Continuation of "GNUNET_FS_publish_ksk" that performs the actual
159 * publishing operation (iterating over all of the keywords).
161 * @param cls closure of type "struct GNUNET_FS_PublishKskContext*"
165 publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
167 struct GNUNET_FS_PublishKskContext *pkc = cls;
169 struct GNUNET_HashCode key;
170 struct GNUNET_HashCode seed;
171 struct GNUNET_HashCode signing_key;
172 struct GNUNET_HashCode query;
173 struct GNUNET_CRYPTO_AesSessionKey skey;
174 struct GNUNET_CRYPTO_AesInitializationVector iv;
175 struct GNUNET_FS_PseudonymHandle *ph;
176 struct GNUNET_FS_PseudonymIdentifier pseudonym;
178 pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK;
179 if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || (NULL == pkc->dsh))
181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "KSK PUT operation complete\n");
182 pkc->cont (pkc->cont_cls, pkc->ksk_uri, NULL);
183 GNUNET_FS_publish_ksk_cancel (pkc);
186 /* derive signing seed from plaintext */
187 GNUNET_CRYPTO_hash (&pkc->ub[1],
188 1 + pkc->slen + pkc->mdsize,
190 keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under keyword `%s'\n",
193 /* first character of keyword indicates if it is
194 * mandatory or not -- ignore for hashing */
195 GNUNET_CRYPTO_hash (&keyword[1], strlen (&keyword[1]), &key);
196 GNUNET_CRYPTO_hash_to_aes_key (&key, &skey, &iv);
197 GNUNET_CRYPTO_aes_encrypt (&pkc->ub[1],
198 1 + pkc->slen + pkc->mdsize,
201 ph = GNUNET_FS_pseudonym_get_anonymous_pseudonym_handle ();
202 GNUNET_CRYPTO_hash (&key, sizeof (key), &signing_key);
203 pkc->cpy->purpose.size = htonl (1 + pkc->slen + pkc->mdsize + sizeof (struct UBlock)
204 - sizeof (struct GNUNET_FS_PseudonymSignature));
205 pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK);
206 GNUNET_FS_pseudonym_sign (ph,
210 &pkc->cpy->signature);
211 GNUNET_FS_pseudonym_get_identifier (ph, &pseudonym);
212 GNUNET_FS_pseudonym_derive_verification_key (&pseudonym,
214 &pkc->cpy->verification_key);
215 GNUNET_CRYPTO_hash (&pkc->cpy->verification_key,
216 sizeof (pkc->cpy->verification_key),
218 GNUNET_FS_pseudonym_destroy (ph);
220 GNUNET_DATASTORE_put (pkc->dsh, 0, &query,
221 1 + pkc->slen + pkc->mdsize + sizeof (struct UBlock),
222 pkc->cpy, GNUNET_BLOCK_TYPE_FS_UBLOCK,
223 pkc->bo.content_priority, pkc->bo.anonymity_level,
224 pkc->bo.replication_level, pkc->bo.expiration_time,
225 -2, 1, GNUNET_CONSTANTS_SERVICE_TIMEOUT,
231 * Publish a CHK under various keywords on GNUnet.
233 * @param h handle to the file sharing subsystem
234 * @param ksk_uri keywords to use
235 * @param meta metadata to use
236 * @param uri URI to refer to in the KBlock
237 * @param bo per-block options
238 * @param options publication options
239 * @param cont continuation
240 * @param cont_cls closure for cont
241 * @return NULL on error ('cont' will still be called)
243 struct GNUNET_FS_PublishKskContext *
244 GNUNET_FS_publish_ksk (struct GNUNET_FS_Handle *h,
245 const struct GNUNET_FS_Uri *ksk_uri,
246 const struct GNUNET_CONTAINER_MetaData *meta,
247 const struct GNUNET_FS_Uri *uri,
248 const struct GNUNET_FS_BlockOptions *bo,
249 enum GNUNET_FS_PublishOptions options,
250 GNUNET_FS_PublishContinuation cont, void *cont_cls)
252 struct GNUNET_FS_PublishKskContext *pkc;
258 GNUNET_assert (NULL != uri);
259 pkc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishKskContext));
263 pkc->cont_cls = cont_cls;
264 if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
266 pkc->dsh = GNUNET_DATASTORE_connect (h->cfg);
267 if (NULL == pkc->dsh)
269 cont (cont_cls, NULL, _("Could not connect to datastore."));
277 pkc->mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
278 GNUNET_assert (pkc->mdsize >= 0);
279 uris = GNUNET_FS_uri_to_string (uri);
280 pkc->slen = strlen (uris) + 1;
281 size = pkc->mdsize + sizeof (struct UBlock) + pkc->slen + 1;
282 if (size > MAX_UBLOCK_SIZE)
284 size = MAX_UBLOCK_SIZE;
285 pkc->mdsize = size - sizeof (struct UBlock) - pkc->slen + 1;
287 pkc->ub = GNUNET_malloc (size);
288 kbe = (char *) &pkc->ub[1];
289 kbe++; /* leave one '\0' for the update identifier */
290 memcpy (kbe, uris, pkc->slen);
292 sptr = &kbe[pkc->slen];
295 GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, pkc->mdsize,
296 GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
297 if (-1 == pkc->mdsize)
300 GNUNET_free (pkc->ub);
301 if (NULL != pkc->dsh)
303 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
307 cont (cont_cls, NULL, _("Internal error."));
310 size = sizeof (struct UBlock) + pkc->slen + pkc->mdsize + 1;
312 pkc->cpy = GNUNET_malloc (size);
313 pkc->cpy->purpose.size =
314 htonl (sizeof (struct GNUNET_FS_PseudonymSignaturePurpose) +
315 pkc->mdsize + pkc->slen + 1);
316 pkc->cpy->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK);
317 pkc->ksk_uri = GNUNET_FS_uri_dup (ksk_uri);
318 pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
324 * Abort the KSK publishing operation.
326 * @param pkc context of the operation to abort.
329 GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc)
331 if (GNUNET_SCHEDULER_NO_TASK != pkc->ksk_task)
333 GNUNET_SCHEDULER_cancel (pkc->ksk_task);
334 pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK;
336 if (NULL != pkc->qre)
338 GNUNET_DATASTORE_cancel (pkc->qre);
341 if (NULL != pkc->dsh)
343 GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
346 GNUNET_free (pkc->cpy);
347 GNUNET_free (pkc->ub);
348 GNUNET_FS_uri_destroy (pkc->ksk_uri);
353 /* end of fs_publish_ksk.c */