fs_publish_ublock.c 9.0 KB

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