renaming GNUNET_PSEUDONYM_-API to GNUNET_FS_pseudonym-API
[oweals/gnunet.git] / src / fs / fs_publish_ksk.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2012, 2013 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20
21 /**
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
27  */
28
29 #include "platform.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_signatures.h"
32 #include "gnunet_util_lib.h"
33 #include "gnunet_fs_service.h"
34 #include "fs_api.h"
35 #include "fs_tree.h"
36
37
38 /**
39  * Context for the KSK publication.
40  */
41 struct GNUNET_FS_PublishKskContext
42 {
43
44   /**
45    * Keywords to use.
46    */
47   struct GNUNET_FS_Uri *ksk_uri;
48
49   /**
50    * Global FS context.
51    */
52   struct GNUNET_FS_Handle *h;
53
54   /**
55    * The master block that we are sending
56    * (in plaintext), has "mdsize+slen" more
57    * bytes than the struct would suggest.
58    */
59   struct UBlock *ub;
60
61   /**
62    * Buffer of the same size as "kb" for
63    * the encrypted version.
64    */
65   struct UBlock *cpy;
66
67   /**
68    * Handle to the datastore, NULL if we are just
69    * simulating.
70    */
71   struct GNUNET_DATASTORE_Handle *dsh;
72
73   /**
74    * Handle to datastore PUT request.
75    */
76   struct GNUNET_DATASTORE_QueueEntry *qre;
77
78   /**
79    * Current task.
80    */
81   GNUNET_SCHEDULER_TaskIdentifier ksk_task;
82
83   /**
84    * Function to call once we're done.
85    */
86   GNUNET_FS_PublishContinuation cont;
87
88   /**
89    * Closure for cont.
90    */
91   void *cont_cls;
92
93   /**
94    * When should the KBlocks expire?
95    */
96   struct GNUNET_FS_BlockOptions bo;
97
98   /**
99    * Size of the serialized metadata.
100    */
101   ssize_t mdsize;
102
103   /**
104    * Size of the (CHK) URI as a string.
105    */
106   size_t slen;
107
108   /**
109    * Keyword that we are currently processing.
110    */
111   unsigned int i;
112
113 };
114
115
116 /**
117  * Continuation of "GNUNET_FS_publish_ksk" that performs
118  * the actual publishing operation (iterating over all
119  * of the keywords).
120  *
121  * @param cls closure of type "struct PublishKskContext*"
122  * @param tc unused
123  */
124 static void
125 publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
126
127
128 /**
129  * Function called by the datastore API with
130  * the result from the PUT request.
131  *
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)
136  */
137 static void
138 kb_put_cont (void *cls, int success, 
139              struct GNUNET_TIME_Absolute min_expiration,
140              const char *msg)
141 {
142   struct GNUNET_FS_PublishKskContext *pkc = cls;
143
144   pkc->qre = NULL;
145   if (GNUNET_OK != success)
146   {
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);
151     return;
152   }
153   pkc->ksk_task = GNUNET_SCHEDULER_add_now (&publish_ksk_cont, pkc);
154 }
155
156
157 /**
158  * Continuation of "GNUNET_FS_publish_ksk" that performs the actual
159  * publishing operation (iterating over all of the keywords).
160  *
161  * @param cls closure of type "struct GNUNET_FS_PublishKskContext*"
162  * @param tc unused
163  */
164 static void
165 publish_ksk_cont (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
166 {
167   struct GNUNET_FS_PublishKskContext *pkc = cls;
168   const char *keyword;
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;
177
178   pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK;
179   if ((pkc->i == pkc->ksk_uri->data.ksk.keywordCount) || (NULL == pkc->dsh))
180   {
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);
184     return;
185   }
186   /* derive signing seed from plaintext */
187   GNUNET_CRYPTO_hash (&pkc->ub[1],
188                       1 + pkc->slen + pkc->mdsize,
189                       &seed);
190   keyword = pkc->ksk_uri->data.ksk.keywords[pkc->i++];
191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Publishing under keyword `%s'\n",
192               &keyword[1]);  
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,
199                              &skey, &iv,
200                              &pkc->cpy[1]);
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,
207                          &pkc->cpy->purpose,
208                          &seed,
209                          &signing_key,
210                          &pkc->cpy->signature);
211   GNUNET_FS_pseudonym_get_identifier (ph, &pseudonym);
212   GNUNET_FS_pseudonym_derive_verification_key (&pseudonym, 
213                                             &signing_key,
214                                             &pkc->cpy->verification_key);
215   GNUNET_CRYPTO_hash (&pkc->cpy->verification_key,
216                       sizeof (pkc->cpy->verification_key),
217                       &query);
218   GNUNET_FS_pseudonym_destroy (ph);
219   pkc->qre =
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,
226                             &kb_put_cont, pkc);
227 }
228
229
230 /**
231  * Publish a CHK under various keywords on GNUnet.
232  *
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)
242  */
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)
251 {
252   struct GNUNET_FS_PublishKskContext *pkc;
253   char *uris;
254   size_t size;
255   char *kbe;
256   char *sptr;
257
258   GNUNET_assert (NULL != uri);
259   pkc = GNUNET_malloc (sizeof (struct GNUNET_FS_PublishKskContext));
260   pkc->h = h;
261   pkc->bo = *bo;
262   pkc->cont = cont;
263   pkc->cont_cls = cont_cls;
264   if (0 == (options & GNUNET_FS_PUBLISH_OPTION_SIMULATE_ONLY))
265   {
266     pkc->dsh = GNUNET_DATASTORE_connect (h->cfg);
267     if (NULL == pkc->dsh)
268     {
269       cont (cont_cls, NULL, _("Could not connect to datastore."));
270       GNUNET_free (pkc);
271       return NULL;
272     }
273   }
274   if (meta == NULL)
275     pkc->mdsize = 0;
276   else
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)
283   {
284     size = MAX_UBLOCK_SIZE;
285     pkc->mdsize = size - sizeof (struct UBlock) - pkc->slen + 1;
286   }
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);
291   GNUNET_free (uris);
292   sptr = &kbe[pkc->slen];
293   if (meta != NULL)
294     pkc->mdsize =
295         GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, pkc->mdsize,
296                                               GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
297   if (-1 == pkc->mdsize)
298   {
299     GNUNET_break (0);
300     GNUNET_free (pkc->ub);
301     if (NULL != pkc->dsh)
302     {
303       GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
304       pkc->dsh = NULL;
305     }
306     GNUNET_free (pkc);
307     cont (cont_cls, NULL, _("Internal error."));
308     return NULL;
309   }
310   size = sizeof (struct UBlock) + pkc->slen + pkc->mdsize + 1;
311
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);
319   return pkc;
320 }
321
322
323 /**
324  * Abort the KSK publishing operation.
325  *
326  * @param pkc context of the operation to abort.
327  */
328 void
329 GNUNET_FS_publish_ksk_cancel (struct GNUNET_FS_PublishKskContext *pkc)
330 {
331   if (GNUNET_SCHEDULER_NO_TASK != pkc->ksk_task)
332   {
333     GNUNET_SCHEDULER_cancel (pkc->ksk_task);
334     pkc->ksk_task = GNUNET_SCHEDULER_NO_TASK;
335   }
336   if (NULL != pkc->qre)
337   {
338     GNUNET_DATASTORE_cancel (pkc->qre);
339     pkc->qre = NULL;
340   }
341   if (NULL != pkc->dsh)
342   {
343     GNUNET_DATASTORE_disconnect (pkc->dsh, GNUNET_NO);
344     pkc->dsh = NULL;
345   }
346   GNUNET_free (pkc->cpy);
347   GNUNET_free (pkc->ub);
348   GNUNET_FS_uri_destroy (pkc->ksk_uri);
349   GNUNET_free (pkc);
350 }
351
352
353 /* end of fs_publish_ksk.c */