gnsrecord_crypto.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009-2013, 2018 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 gnsrecord/gnsrecord_crypto.c
  18. * @brief API for GNS record-related crypto
  19. * @author Martin Schanzenbach
  20. * @author Matthias Wachs
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_constants.h"
  26. #include "gnunet_signatures.h"
  27. #include "gnunet_arm_service.h"
  28. #include "gnunet_gnsrecord_lib.h"
  29. #include "gnunet_dnsparser_lib.h"
  30. #include "gnunet_tun_lib.h"
  31. #define LOG(kind,...) GNUNET_log_from (kind, "gnsrecord",__VA_ARGS__)
  32. /**
  33. * Derive session key and iv from label and public key.
  34. *
  35. * @param iv initialization vector to initialize
  36. * @param skey session key to initialize
  37. * @param label label to use for KDF
  38. * @param pub public key to use for KDF
  39. */
  40. static void
  41. derive_block_aes_key (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
  42. struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
  43. const char *label,
  44. const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
  45. {
  46. static const char ctx_key[] = "gns-aes-ctx-key";
  47. static const char ctx_iv[] = "gns-aes-ctx-iv";
  48. GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
  49. pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
  50. label, strlen (label),
  51. ctx_key, strlen (ctx_key),
  52. NULL, 0);
  53. GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
  54. pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
  55. label, strlen (label),
  56. ctx_iv, strlen (ctx_iv),
  57. NULL, 0);
  58. }
  59. /**
  60. * Sign name and records
  61. *
  62. * @param key the private key
  63. * @param pkey associated public key
  64. * @param expire block expiration
  65. * @param label the name for the records
  66. * @param rd record data
  67. * @param rd_count number of records
  68. * @return NULL on error (block too large)
  69. */
  70. struct GNUNET_GNSRECORD_Block *
  71. block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
  72. const struct GNUNET_CRYPTO_EcdsaPublicKey *pkey,
  73. struct GNUNET_TIME_Absolute expire,
  74. const char *label,
  75. const struct GNUNET_GNSRECORD_Data *rd,
  76. unsigned int rd_count)
  77. {
  78. ssize_t payload_len = GNUNET_GNSRECORD_records_get_size (rd_count,
  79. rd);
  80. struct GNUNET_GNSRECORD_Block *block;
  81. struct GNUNET_CRYPTO_EcdsaPrivateKey *dkey;
  82. struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  83. struct GNUNET_CRYPTO_SymmetricSessionKey skey;
  84. struct GNUNET_GNSRECORD_Data rdc[GNUNET_NZL(rd_count)];
  85. uint32_t rd_count_nbo;
  86. struct GNUNET_TIME_Absolute now;
  87. if (payload_len < 0)
  88. {
  89. GNUNET_break (0);
  90. return NULL;
  91. }
  92. if (payload_len > GNUNET_GNSRECORD_MAX_BLOCK_SIZE)
  93. {
  94. GNUNET_break (0);
  95. return NULL;
  96. }
  97. /* convert relative to absolute times */
  98. now = GNUNET_TIME_absolute_get ();
  99. for (unsigned int i=0;i<rd_count;i++)
  100. {
  101. rdc[i] = rd[i];
  102. if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
  103. {
  104. struct GNUNET_TIME_Relative t;
  105. /* encrypted blocks must never have relative expiration times, convert! */
  106. rdc[i].flags &= ~GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION;
  107. t.rel_value_us = rdc[i].expiration_time;
  108. rdc[i].expiration_time = GNUNET_TIME_absolute_add (now, t).abs_value_us;
  109. }
  110. }
  111. /* serialize */
  112. rd_count_nbo = htonl (rd_count);
  113. {
  114. char payload[sizeof (uint32_t) + payload_len];
  115. GNUNET_memcpy (payload,
  116. &rd_count_nbo,
  117. sizeof (uint32_t));
  118. GNUNET_assert (payload_len ==
  119. GNUNET_GNSRECORD_records_serialize (rd_count,
  120. rdc,
  121. payload_len,
  122. &payload[sizeof (uint32_t)]));
  123. block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) +
  124. sizeof (uint32_t) +
  125. payload_len);
  126. block->purpose.size = htonl (sizeof (uint32_t) +
  127. payload_len +
  128. sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
  129. sizeof (struct GNUNET_TIME_AbsoluteNBO));
  130. block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN);
  131. block->expiration_time = GNUNET_TIME_absolute_hton (expire);
  132. /* encrypt and sign */
  133. dkey = GNUNET_CRYPTO_ecdsa_private_key_derive (key,
  134. label,
  135. "gns");
  136. GNUNET_CRYPTO_ecdsa_key_get_public (dkey,
  137. &block->derived_key);
  138. derive_block_aes_key (&iv,
  139. &skey,
  140. label,
  141. pkey);
  142. GNUNET_break (payload_len + sizeof (uint32_t) ==
  143. GNUNET_CRYPTO_symmetric_encrypt (payload,
  144. payload_len + sizeof (uint32_t),
  145. &skey,
  146. &iv,
  147. &block[1]));
  148. }
  149. if (GNUNET_OK !=
  150. GNUNET_CRYPTO_ecdsa_sign (dkey,
  151. &block->purpose,
  152. &block->signature))
  153. {
  154. GNUNET_break (0);
  155. GNUNET_free (dkey);
  156. GNUNET_free (block);
  157. return NULL;
  158. }
  159. GNUNET_free (dkey);
  160. return block;
  161. }
  162. /**
  163. * Sign name and records
  164. *
  165. * @param key the private key
  166. * @param expire block expiration
  167. * @param label the name for the records
  168. * @param rd record data
  169. * @param rd_count number of records
  170. * @return NULL on error (block too large)
  171. */
  172. struct GNUNET_GNSRECORD_Block *
  173. GNUNET_GNSRECORD_block_create (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
  174. struct GNUNET_TIME_Absolute expire,
  175. const char *label,
  176. const struct GNUNET_GNSRECORD_Data *rd,
  177. unsigned int rd_count)
  178. {
  179. struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
  180. GNUNET_CRYPTO_ecdsa_key_get_public (key,
  181. &pkey);
  182. return block_create (key,
  183. &pkey,
  184. expire,
  185. label,
  186. rd,
  187. rd_count);
  188. }
  189. /**
  190. * Line in cache mapping private keys to public keys.
  191. */
  192. struct KeyCacheLine
  193. {
  194. /**
  195. * A private key.
  196. */
  197. struct GNUNET_CRYPTO_EcdsaPrivateKey key;
  198. /**
  199. * Associated public key.
  200. */
  201. struct GNUNET_CRYPTO_EcdsaPublicKey pkey;
  202. };
  203. /**
  204. * Sign name and records, cache derived public key (also keeps the
  205. * private key in static memory, so do not use this function if
  206. * keeping the private key in the process'es RAM is a major issue).
  207. *
  208. * @param key the private key
  209. * @param expire block expiration
  210. * @param label the name for the records
  211. * @param rd record data
  212. * @param rd_count number of records
  213. * @return NULL on error (block too large)
  214. */
  215. struct GNUNET_GNSRECORD_Block *
  216. GNUNET_GNSRECORD_block_create2 (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
  217. struct GNUNET_TIME_Absolute expire,
  218. const char *label,
  219. const struct GNUNET_GNSRECORD_Data *rd,
  220. unsigned int rd_count)
  221. {
  222. #define CSIZE 64
  223. static struct KeyCacheLine cache[CSIZE];
  224. struct KeyCacheLine *line;
  225. line = &cache[(*(unsigned int *) key) % CSIZE];
  226. if (0 != memcmp (&line->key,
  227. key,
  228. sizeof (*key)))
  229. {
  230. /* cache miss, recompute */
  231. line->key = *key;
  232. GNUNET_CRYPTO_ecdsa_key_get_public (key,
  233. &line->pkey);
  234. }
  235. #undef CSIZE
  236. return block_create (key,
  237. &line->pkey,
  238. expire,
  239. label,
  240. rd,
  241. rd_count);
  242. }
  243. /**
  244. * Check if a signature is valid. This API is used by the GNS Block
  245. * to validate signatures received from the network.
  246. *
  247. * @param block block to verify
  248. * @return #GNUNET_OK if the signature is valid
  249. */
  250. int
  251. GNUNET_GNSRECORD_block_verify (const struct GNUNET_GNSRECORD_Block *block)
  252. {
  253. return GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN,
  254. &block->purpose,
  255. &block->signature,
  256. &block->derived_key);
  257. }
  258. /**
  259. * Decrypt block.
  260. *
  261. * @param block block to decrypt
  262. * @param zone_key public key of the zone
  263. * @param label the name for the records
  264. * @param proc function to call with the result
  265. * @param proc_cls closure for proc
  266. * @return #GNUNET_OK on success, #GNUNET_SYSERR if the block was
  267. * not well-formed
  268. */
  269. int
  270. GNUNET_GNSRECORD_block_decrypt (const struct GNUNET_GNSRECORD_Block *block,
  271. const struct GNUNET_CRYPTO_EcdsaPublicKey *zone_key,
  272. const char *label,
  273. GNUNET_GNSRECORD_RecordCallback proc,
  274. void *proc_cls)
  275. {
  276. size_t payload_len = ntohl (block->purpose.size) -
  277. sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) -
  278. sizeof (struct GNUNET_TIME_AbsoluteNBO);
  279. struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
  280. struct GNUNET_CRYPTO_SymmetricSessionKey skey;
  281. if (ntohl (block->purpose.size) <
  282. sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
  283. sizeof (struct GNUNET_TIME_AbsoluteNBO))
  284. {
  285. GNUNET_break_op (0);
  286. return GNUNET_SYSERR;
  287. }
  288. derive_block_aes_key (&iv,
  289. &skey,
  290. label,
  291. zone_key);
  292. {
  293. char payload[payload_len];
  294. uint32_t rd_count;
  295. GNUNET_break (payload_len ==
  296. GNUNET_CRYPTO_symmetric_decrypt (&block[1], payload_len,
  297. &skey, &iv,
  298. payload));
  299. GNUNET_memcpy (&rd_count,
  300. payload,
  301. sizeof (uint32_t));
  302. rd_count = ntohl (rd_count);
  303. if (rd_count > 2048)
  304. {
  305. /* limit to sane value */
  306. GNUNET_break_op (0);
  307. return GNUNET_SYSERR;
  308. }
  309. {
  310. struct GNUNET_GNSRECORD_Data rd[GNUNET_NZL(rd_count)];
  311. unsigned int j;
  312. struct GNUNET_TIME_Absolute now;
  313. if (GNUNET_OK !=
  314. GNUNET_GNSRECORD_records_deserialize (payload_len - sizeof (uint32_t),
  315. &payload[sizeof (uint32_t)],
  316. rd_count,
  317. rd))
  318. {
  319. GNUNET_break_op (0);
  320. return GNUNET_SYSERR;
  321. }
  322. /* hide expired records */
  323. now = GNUNET_TIME_absolute_get ();
  324. j = 0;
  325. for (unsigned int i=0;i<rd_count;i++)
  326. {
  327. if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION))
  328. {
  329. /* encrypted blocks must never have relative expiration times, skip! */
  330. GNUNET_break_op (0);
  331. continue;
  332. }
  333. if (0 != (rd[i].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD))
  334. {
  335. int include_record = GNUNET_YES;
  336. /* Shadow record, figure out if we have a not expired active record */
  337. for (unsigned int k=0;k<rd_count;k++)
  338. {
  339. if (k == i)
  340. continue;
  341. if (rd[i].expiration_time < now.abs_value_us)
  342. include_record = GNUNET_NO; /* Shadow record is expired */
  343. if ( (rd[k].record_type == rd[i].record_type) &&
  344. (rd[k].expiration_time >= now.abs_value_us) &&
  345. (0 == (rd[k].flags & GNUNET_GNSRECORD_RF_SHADOW_RECORD)) )
  346. {
  347. include_record = GNUNET_NO; /* We have a non-expired, non-shadow record of the same type */
  348. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  349. "Ignoring shadow record\n");
  350. break;
  351. }
  352. }
  353. if (GNUNET_YES == include_record)
  354. {
  355. rd[i].flags ^= GNUNET_GNSRECORD_RF_SHADOW_RECORD; /* Remove Flag */
  356. if (j != i)
  357. rd[j] = rd[i];
  358. j++;
  359. }
  360. }
  361. else if (rd[i].expiration_time >= now.abs_value_us)
  362. {
  363. /* Include this record */
  364. if (j != i)
  365. rd[j] = rd[i];
  366. j++;
  367. }
  368. else
  369. {
  370. struct GNUNET_TIME_Absolute at;
  371. at.abs_value_us = rd[i].expiration_time;
  372. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  373. "Excluding record that expired %s (%llu ago)\n",
  374. GNUNET_STRINGS_absolute_time_to_string (at),
  375. (unsigned long long) rd[i].expiration_time - now.abs_value_us);
  376. }
  377. }
  378. rd_count = j;
  379. if (NULL != proc)
  380. proc (proc_cls,
  381. rd_count,
  382. (0 != rd_count) ? rd : NULL);
  383. }
  384. }
  385. return GNUNET_OK;
  386. }
  387. /**
  388. * Calculate the DHT query for a given @a label in a given @a zone.
  389. *
  390. * @param zone private key of the zone
  391. * @param label label of the record
  392. * @param query hash to use for the query
  393. */
  394. void
  395. GNUNET_GNSRECORD_query_from_private_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
  396. const char *label,
  397. struct GNUNET_HashCode *query)
  398. {
  399. struct GNUNET_CRYPTO_EcdsaPublicKey pub;
  400. GNUNET_CRYPTO_ecdsa_key_get_public (zone,
  401. &pub);
  402. GNUNET_GNSRECORD_query_from_public_key (&pub,
  403. label,
  404. query);
  405. }
  406. /**
  407. * Calculate the DHT query for a given @a label in a given @a zone.
  408. *
  409. * @param pub public key of the zone
  410. * @param label label of the record
  411. * @param query hash to use for the query
  412. */
  413. void
  414. GNUNET_GNSRECORD_query_from_public_key (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
  415. const char *label,
  416. struct GNUNET_HashCode *query)
  417. {
  418. struct GNUNET_CRYPTO_EcdsaPublicKey pd;
  419. GNUNET_CRYPTO_ecdsa_public_key_derive (pub,
  420. label,
  421. "gns",
  422. &pd);
  423. GNUNET_CRYPTO_hash (&pd,
  424. sizeof (pd),
  425. query);
  426. }
  427. /* end of gnsrecord_crypto.c */