fs_publish_ublock.c 9.2 KB

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