glitch in the license text detected by hyazinthe, thank you!
[oweals/gnunet.git] / src / fs / fs_publish_ublock.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2012, 2013 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14 */
15
16 /**
17  * @file fs/fs_publish_ublock.c
18  * @brief publish a UBLOCK in GNUnet
19  * @see https://gnunet.org/encoding and #2564
20  * @author Krista Bennett
21  * @author Christian Grothoff
22  */
23 #include "platform.h"
24 #include "gnunet_constants.h"
25 #include "gnunet_signatures.h"
26 #include "fs_publish_ublock.h"
27 #include "fs_api.h"
28 #include "fs_tree.h"
29
30
31 /**
32  * Derive the key for symmetric encryption/decryption from
33  * the public key and the label.
34  *
35  * @param skey where to store symmetric key
36  * @param iv where to store the IV
37  * @param label label to use for key derivation
38  * @param pub public key to use for key derivation
39  */
40 static void
41 derive_ublock_encryption_key (struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
42                               struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
43                               const char *label,
44                               const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
45 {
46   struct GNUNET_HashCode key;
47
48   /* derive key from 'label' and public key of the namespace */
49   GNUNET_assert (GNUNET_YES ==
50                  GNUNET_CRYPTO_kdf (&key, sizeof (key),
51                                     "UBLOCK-ENC", strlen ("UBLOCK-ENC"),
52                                     label, strlen (label),
53                                     pub, sizeof (*pub),
54                                     NULL, 0));
55   GNUNET_CRYPTO_hash_to_aes_key (&key, skey, iv);
56 }
57
58
59 /**
60  * Decrypt the given UBlock, storing the result in output.
61  *
62  * @param input input data
63  * @param input_len number of bytes in @a input
64  * @param ns public key under which the UBlock was stored
65  * @param label label under which the UBlock was stored
66  * @param output where to write the result, has input_len bytes
67  */
68 void
69 GNUNET_FS_ublock_decrypt_ (const void *input,
70                            size_t input_len,
71                            const struct GNUNET_CRYPTO_EcdsaPublicKey *ns,
72                            const char *label,
73                            void *output)
74 {
75   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
76   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
77
78   derive_ublock_encryption_key (&skey, &iv,
79                                 label, ns);
80   GNUNET_CRYPTO_symmetric_decrypt (input, input_len,
81                              &skey, &iv,
82                              output);
83 }
84
85
86 /**
87  * Context for 'ublock_put_cont'.
88  */
89 struct GNUNET_FS_PublishUblockContext
90 {
91
92   /**
93    * Function to call when done.
94    */
95   GNUNET_FS_UBlockContinuation cont;
96
97   /**
98    * Closure of 'cont'.
99    */
100   void *cont_cls;
101
102   /**
103    * Handle for active datastore operation.
104    */
105   struct GNUNET_DATASTORE_QueueEntry *qre;
106
107   /**
108    * Task to run continuation asynchronously.
109    */
110   struct GNUNET_SCHEDULER_Task * task;
111
112 };
113
114
115 /**
116  * Continuation of #GNUNET_FS_publish_ublock_().
117  *
118  * @param cls closure of type "struct GNUNET_FS_PublishUblockContext*"
119  * @param success #GNUNET_SYSERR on failure (including timeout/queue drop)
120  *                #GNUNET_NO if content was already there
121  *                #GNUNET_YES (or other positive value) on success
122  * @param min_expiration minimum expiration time required for 0-priority content to be stored
123  *                by the datacache at this time, zero for unknown, forever if we have no
124  *                space for 0-priority content
125  * @param msg NULL on success, otherwise an error message
126  */
127 static void
128 ublock_put_cont (void *cls,
129                  int32_t success,
130                  struct GNUNET_TIME_Absolute min_expiration,
131                  const char *msg)
132 {
133   struct GNUNET_FS_PublishUblockContext *uc = cls;
134
135   uc->qre = NULL;
136   uc->cont (uc->cont_cls, msg);
137   GNUNET_free (uc);
138 }
139
140
141 /**
142  * Run the continuation.
143  *
144  * @param cls the `struct GNUNET_FS_PublishUblockContext *`
145  */
146 static void
147 run_cont (void *cls)
148 {
149   struct GNUNET_FS_PublishUblockContext *uc = cls;
150
151   uc->task = NULL;
152   uc->cont (uc->cont_cls, NULL);
153   GNUNET_free (uc);
154 }
155
156
157 /**
158  * Publish a UBlock.
159  *
160  * @param h handle to the file sharing subsystem
161  * @param dsh datastore handle to use for storage operation
162  * @param label identifier to use
163  * @param ulabel update label to use, may be an empty string for none
164  * @param ns namespace to publish in
165  * @param meta metadata to use
166  * @param uri URI to refer to in the UBlock
167  * @param bo per-block options
168  * @param options publication options
169  * @param cont continuation
170  * @param cont_cls closure for @a cont
171  * @return NULL on error (@a cont will still be called)
172  */
173 struct GNUNET_FS_PublishUblockContext *
174 GNUNET_FS_publish_ublock_ (struct GNUNET_FS_Handle *h,
175                            struct GNUNET_DATASTORE_Handle *dsh,
176                            const char *label,
177                            const char *ulabel,
178                            const struct GNUNET_CRYPTO_EcdsaPrivateKey *ns,
179                            const struct GNUNET_CONTAINER_MetaData *meta,
180                            const struct GNUNET_FS_Uri *uri,
181                            const struct GNUNET_FS_BlockOptions *bo,
182                            enum GNUNET_FS_PublishOptions options,
183                            GNUNET_FS_UBlockContinuation cont, void *cont_cls)
184 {
185   struct GNUNET_FS_PublishUblockContext *uc;
186   struct GNUNET_HashCode query;
187   struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
188   struct GNUNET_CRYPTO_SymmetricSessionKey skey;
189   struct GNUNET_CRYPTO_EcdsaPrivateKey *nsd;
190   struct GNUNET_CRYPTO_EcdsaPublicKey pub;
191   char *uris;
192   size_t size;
193   char *kbe;
194   char *sptr;
195   ssize_t mdsize;
196   size_t slen;
197   size_t ulen;
198   struct UBlock *ub_plain;
199   struct UBlock *ub_enc;
200
201   /* compute ublock to publish */
202   if (NULL == meta)
203     mdsize = 0;
204   else
205     mdsize = GNUNET_CONTAINER_meta_data_get_serialized_size (meta);
206   GNUNET_assert (mdsize >= 0);
207   uris = GNUNET_FS_uri_to_string (uri);
208   slen = strlen (uris) + 1;
209   if (NULL == ulabel)
210     ulen = 1;
211   else
212     ulen = strlen (ulabel) + 1;
213   size = mdsize + sizeof (struct UBlock) + slen + ulen;
214   if (size > MAX_UBLOCK_SIZE)
215   {
216     size = MAX_UBLOCK_SIZE;
217     mdsize = size - sizeof (struct UBlock) - (slen + ulen);
218   }
219   ub_plain = GNUNET_malloc (size);
220   kbe = (char *) &ub_plain[1];
221   if (NULL != ulabel)
222     GNUNET_memcpy (kbe, ulabel, ulen);
223   kbe += ulen;
224   GNUNET_memcpy (kbe, uris, slen);
225   kbe += slen;
226   GNUNET_free (uris);
227   sptr = kbe;
228   if (NULL != meta)
229     mdsize =
230       GNUNET_CONTAINER_meta_data_serialize (meta, &sptr, mdsize,
231                                             GNUNET_CONTAINER_META_DATA_SERIALIZE_PART);
232   if (-1 == mdsize)
233   {
234     GNUNET_break (0);
235     GNUNET_free (ub_plain);
236     cont (cont_cls, _("Internal error."));
237     return NULL;
238   }
239   size = sizeof (struct UBlock) + slen + mdsize + ulen;
240
241   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
242               "Publishing under identifier `%s'\n",
243               label);
244   /* get public key of the namespace */
245   GNUNET_CRYPTO_ecdsa_key_get_public (ns,
246                                     &pub);
247   derive_ublock_encryption_key (&skey, &iv,
248                                 label, &pub);
249
250   /* encrypt ublock */
251   ub_enc = GNUNET_malloc (size);
252   GNUNET_CRYPTO_symmetric_encrypt (&ub_plain[1],
253                              ulen + slen + mdsize,
254                              &skey, &iv,
255                              &ub_enc[1]);
256   GNUNET_free (ub_plain);
257   ub_enc->purpose.size = htonl (ulen + slen + mdsize +
258                                 sizeof (struct UBlock)
259                                 - sizeof (struct GNUNET_CRYPTO_EcdsaSignature));
260   ub_enc->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_FS_UBLOCK);
261
262   /* derive signing-key from 'label' and public key of the namespace */
263   nsd = GNUNET_CRYPTO_ecdsa_private_key_derive (ns, label, "fs-ublock");
264   GNUNET_CRYPTO_ecdsa_key_get_public (nsd,
265                                     &ub_enc->verification_key);
266   GNUNET_assert (GNUNET_OK ==
267                  GNUNET_CRYPTO_ecdsa_sign (nsd,
268                                          &ub_enc->purpose,
269                                          &ub_enc->signature));
270   GNUNET_CRYPTO_hash (&ub_enc->verification_key,
271                       sizeof (ub_enc->verification_key),
272                       &query);
273   GNUNET_free (nsd);
274
275   uc = GNUNET_new (struct GNUNET_FS_PublishUblockContext);
276   uc->cont = cont;
277   uc->cont_cls = cont_cls;
278   if (NULL != dsh)
279   {
280     uc->qre =
281       GNUNET_DATASTORE_put (dsh,
282                             0,
283                             &query,
284                             ulen + slen + mdsize + sizeof (struct UBlock),
285                             ub_enc,
286                             GNUNET_BLOCK_TYPE_FS_UBLOCK,
287                             bo->content_priority,
288                             bo->anonymity_level,
289                             bo->replication_level,
290                             bo->expiration_time,
291                             -2, 1,
292                             &ublock_put_cont, uc);
293   }
294   else
295   {
296     uc->task = GNUNET_SCHEDULER_add_now (&run_cont,
297                                          uc);
298   }
299   GNUNET_free (ub_enc);
300   return uc;
301 }
302
303
304 /**
305  * Abort UBlock publishing operation.
306  *
307  * @param uc operation to abort.
308  */
309 void
310 GNUNET_FS_publish_ublock_cancel_ (struct GNUNET_FS_PublishUblockContext *uc)
311 {
312   if (NULL != uc->qre)
313     GNUNET_DATASTORE_cancel (uc->qre);
314   if (NULL != uc->task)
315     GNUNET_SCHEDULER_cancel (uc->task);
316   GNUNET_free (uc);
317 }
318
319 /* end of fs_publish_ublock.c */