You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

curve.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /*
  2. * Copyright (c) 2014, Vsevolod Stakhov
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  18. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include <sys/types.h>
  26. #include <sys/uio.h>
  27. #include <unistd.h>
  28. #include "rdns.h"
  29. #include "dns_private.h"
  30. #include "rdns_curve.h"
  31. #include "ottery.h"
  32. #include "ref.h"
  33. #include "logger.h"
  34. #ifdef TWEETNACL
  35. #include <tweetnacl.h>
  36. void
  37. randombytes(uint8_t *data, uint64_t len)
  38. {
  39. ottery_rand_bytes (data, len);
  40. }
  41. void sodium_memzero (uint8_t *data, uint64_t len)
  42. {
  43. volatile uint8_t *p = data;
  44. while (len--) {
  45. *p = '\0';
  46. }
  47. }
  48. void sodium_init(void)
  49. {
  50. }
  51. ssize_t rdns_curve_send (struct rdns_request *req, void *plugin_data);
  52. ssize_t rdns_curve_recv (struct rdns_io_channel *ioc, void *buf, size_t len,
  53. void *plugin_data, struct rdns_request **req_out);
  54. void rdns_curve_finish_request (struct rdns_request *req, void *plugin_data);
  55. void rdns_curve_dtor (struct rdns_resolver *resolver, void *plugin_data);
  56. struct rdns_curve_entry {
  57. char *name;
  58. unsigned char pk[crypto_box_PUBLICKEYBYTES];
  59. UT_hash_handle hh;
  60. };
  61. struct rdns_curve_nm_entry {
  62. unsigned char k[crypto_box_BEFORENMBYTES];
  63. struct rdns_curve_entry *entry;
  64. struct rdns_curve_nm_entry *prev, *next;
  65. };
  66. struct rdns_curve_client_key {
  67. unsigned char pk[crypto_box_PUBLICKEYBYTES];
  68. unsigned char sk[crypto_box_SECRETKEYBYTES];
  69. struct rdns_curve_nm_entry *nms;
  70. uint64_t counter;
  71. unsigned int uses;
  72. ref_entry_t ref;
  73. };
  74. struct rdns_curve_request {
  75. struct rdns_request *req;
  76. struct rdns_curve_client_key *key;
  77. struct rdns_curve_entry *entry;
  78. struct rdns_curve_nm_entry *nm;
  79. unsigned char nonce[crypto_box_NONCEBYTES];
  80. UT_hash_handle hh;
  81. };
  82. struct rdns_curve_ctx {
  83. struct rdns_curve_entry *entries;
  84. struct rdns_curve_client_key *cur_key;
  85. struct rdns_curve_request *requests;
  86. double key_refresh_interval;
  87. void *key_refresh_event;
  88. struct rdns_resolver *resolver;
  89. };
  90. static struct rdns_curve_client_key *
  91. rdns_curve_client_key_new (struct rdns_curve_ctx *ctx)
  92. {
  93. struct rdns_curve_client_key *new;
  94. struct rdns_curve_nm_entry *nm;
  95. struct rdns_curve_entry *entry, *tmp;
  96. new = calloc (1, sizeof (struct rdns_curve_client_key));
  97. crypto_box_keypair (new->pk, new->sk);
  98. HASH_ITER (hh, ctx->entries, entry, tmp) {
  99. nm = calloc (1, sizeof (struct rdns_curve_nm_entry));
  100. nm->entry = entry;
  101. crypto_box_beforenm (nm->k, entry->pk, new->sk);
  102. DL_APPEND (new->nms, nm);
  103. }
  104. new->counter = ottery_rand_uint64 ();
  105. return new;
  106. }
  107. static struct rdns_curve_nm_entry *
  108. rdns_curve_find_nm (struct rdns_curve_client_key *key, struct rdns_curve_entry *entry)
  109. {
  110. struct rdns_curve_nm_entry *nm;
  111. DL_FOREACH (key->nms, nm) {
  112. if (nm->entry == entry) {
  113. return nm;
  114. }
  115. }
  116. return NULL;
  117. }
  118. static void
  119. rdns_curve_client_key_free (struct rdns_curve_client_key *key)
  120. {
  121. struct rdns_curve_nm_entry *nm, *tmp;
  122. DL_FOREACH_SAFE (key->nms, nm, tmp) {
  123. sodium_memzero (nm->k, sizeof (nm->k));
  124. free (nm);
  125. }
  126. sodium_memzero (key->sk, sizeof (key->sk));
  127. free (key);
  128. }
  129. struct rdns_curve_ctx*
  130. rdns_curve_ctx_new (double key_refresh_interval)
  131. {
  132. struct rdns_curve_ctx *new;
  133. new = calloc (1, sizeof (struct rdns_curve_ctx));
  134. new->key_refresh_interval = key_refresh_interval;
  135. return new;
  136. }
  137. void
  138. rdns_curve_ctx_add_key (struct rdns_curve_ctx *ctx,
  139. const char *name, const unsigned char *pubkey)
  140. {
  141. struct rdns_curve_entry *entry;
  142. bool success = true;
  143. entry = malloc (sizeof (struct rdns_curve_entry));
  144. if (entry != NULL) {
  145. entry->name = strdup (name);
  146. if (entry->name == NULL) {
  147. success = false;
  148. }
  149. memcpy (entry->pk, pubkey, sizeof (entry->pk));
  150. if (success) {
  151. HASH_ADD_KEYPTR (hh, ctx->entries, entry->name, strlen (entry->name), entry);
  152. }
  153. }
  154. }
  155. #define rdns_curve_write_hex(in, out, offset, base) do { \
  156. *(out) |= ((in)[(offset)] - (base)) << ((1 - offset) * 4); \
  157. } while (0)
  158. static bool
  159. rdns_curve_hex_to_byte (const char *in, unsigned char *out)
  160. {
  161. int i;
  162. for (i = 0; i <= 1; i ++) {
  163. if (in[i] >= '0' && in[i] <= '9') {
  164. rdns_curve_write_hex (in, out, i, '0');
  165. }
  166. else if (in[i] >= 'a' && in[i] <= 'f') {
  167. rdns_curve_write_hex (in, out, i, 'a' - 10);
  168. }
  169. else if (in[i] >= 'A' && in[i] <= 'F') {
  170. rdns_curve_write_hex (in, out, i, 'A' - 10);
  171. }
  172. else {
  173. return false;
  174. }
  175. }
  176. return true;
  177. }
  178. #undef rdns_curve_write_hex
  179. unsigned char *
  180. rdns_curve_key_from_hex (const char *hex)
  181. {
  182. unsigned int len = strlen (hex), i;
  183. unsigned char *res = NULL;
  184. if (len == crypto_box_PUBLICKEYBYTES * 2) {
  185. res = calloc (1, crypto_box_PUBLICKEYBYTES);
  186. for (i = 0; i < crypto_box_PUBLICKEYBYTES; i ++) {
  187. if (!rdns_curve_hex_to_byte (&hex[i * 2], &res[i])) {
  188. free (res);
  189. return NULL;
  190. }
  191. }
  192. }
  193. return res;
  194. }
  195. void
  196. rdns_curve_ctx_destroy (struct rdns_curve_ctx *ctx)
  197. {
  198. struct rdns_curve_entry *entry, *tmp;
  199. HASH_ITER (hh, ctx->entries, entry, tmp) {
  200. free (entry->name);
  201. free (entry);
  202. }
  203. free (ctx);
  204. }
  205. static void
  206. rdns_curve_refresh_key_callback (void *user_data)
  207. {
  208. struct rdns_curve_ctx *ctx = user_data;
  209. struct rdns_resolver *resolver;
  210. resolver = ctx->resolver;
  211. rdns_info ("refresh dnscurve keys");
  212. REF_RELEASE (ctx->cur_key);
  213. ctx->cur_key = rdns_curve_client_key_new (ctx);
  214. REF_INIT_RETAIN (ctx->cur_key, rdns_curve_client_key_free);
  215. }
  216. void
  217. rdns_curve_register_plugin (struct rdns_resolver *resolver,
  218. struct rdns_curve_ctx *ctx)
  219. {
  220. struct rdns_plugin *plugin;
  221. if (!resolver->async_binded) {
  222. return;
  223. }
  224. plugin = calloc (1, sizeof (struct rdns_plugin));
  225. if (plugin != NULL) {
  226. plugin->data = ctx;
  227. plugin->type = RDNS_PLUGIN_CURVE;
  228. plugin->cb.curve_plugin.send_cb = rdns_curve_send;
  229. plugin->cb.curve_plugin.recv_cb = rdns_curve_recv;
  230. plugin->cb.curve_plugin.finish_cb = rdns_curve_finish_request;
  231. plugin->dtor = rdns_curve_dtor;
  232. sodium_init ();
  233. ctx->cur_key = rdns_curve_client_key_new (ctx);
  234. REF_INIT_RETAIN (ctx->cur_key, rdns_curve_client_key_free);
  235. if (ctx->key_refresh_interval > 0) {
  236. ctx->key_refresh_event = resolver->async->add_periodic (
  237. resolver->async->data, ctx->key_refresh_interval,
  238. rdns_curve_refresh_key_callback, ctx);
  239. }
  240. ctx->resolver = resolver;
  241. rdns_resolver_register_plugin (resolver, plugin);
  242. }
  243. }
  244. ssize_t
  245. rdns_curve_send (struct rdns_request *req, void *plugin_data)
  246. {
  247. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  248. struct rdns_curve_entry *entry;
  249. struct iovec iov[4];
  250. unsigned char *m;
  251. static const char qmagic[] = "Q6fnvWj8";
  252. struct rdns_curve_request *creq;
  253. struct rdns_curve_nm_entry *nm;
  254. ssize_t ret, boxed_len;
  255. /* Check for key */
  256. HASH_FIND_STR (ctx->entries, req->io->srv->name, entry);
  257. if (entry != NULL) {
  258. nm = rdns_curve_find_nm (ctx->cur_key, entry);
  259. creq = malloc (sizeof (struct rdns_curve_request));
  260. if (creq == NULL) {
  261. return -1;
  262. }
  263. boxed_len = req->pos + crypto_box_ZEROBYTES;
  264. m = malloc (boxed_len);
  265. if (m == NULL) {
  266. return -1;
  267. }
  268. /* Ottery is faster than sodium native PRG that uses /dev/random only */
  269. memcpy (creq->nonce, &ctx->cur_key->counter, sizeof (uint64_t));
  270. ottery_rand_bytes (creq->nonce + sizeof (uint64_t), 12 - sizeof (uint64_t));
  271. sodium_memzero (creq->nonce + 12, crypto_box_NONCEBYTES - 12);
  272. sodium_memzero (m, crypto_box_ZEROBYTES);
  273. memcpy (m + crypto_box_ZEROBYTES, req->packet, req->pos);
  274. if (crypto_box_afternm (m, m, boxed_len,
  275. creq->nonce, nm->k) == -1) {
  276. sodium_memzero (m, boxed_len);
  277. free (m);
  278. return -1;
  279. }
  280. creq->key = ctx->cur_key;
  281. REF_RETAIN (ctx->cur_key);
  282. creq->entry = entry;
  283. creq->req = req;
  284. creq->nm = nm;
  285. HASH_ADD_KEYPTR (hh, ctx->requests, creq->nonce, 12, creq);
  286. req->curve_plugin_data = creq;
  287. ctx->cur_key->counter ++;
  288. ctx->cur_key->uses ++;
  289. /* Now form a dnscurve packet */
  290. iov[0].iov_base = (void *)qmagic;
  291. iov[0].iov_len = sizeof (qmagic) - 1;
  292. iov[1].iov_base = ctx->cur_key->pk;
  293. iov[1].iov_len = sizeof (ctx->cur_key->pk);
  294. iov[2].iov_base = creq->nonce;
  295. iov[2].iov_len = 12;
  296. iov[3].iov_base = m + crypto_box_BOXZEROBYTES;
  297. iov[3].iov_len = boxed_len - crypto_box_BOXZEROBYTES;
  298. ret = writev (req->io->sock, iov, sizeof (iov) / sizeof (iov[0]));
  299. sodium_memzero (m, boxed_len);
  300. free (m);
  301. }
  302. else {
  303. ret = write (req->io->sock, req->packet, req->pos);
  304. req->curve_plugin_data = NULL;
  305. }
  306. return ret;
  307. }
  308. ssize_t
  309. rdns_curve_recv (struct rdns_io_channel *ioc, void *buf, size_t len, void *plugin_data,
  310. struct rdns_request **req_out)
  311. {
  312. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  313. ssize_t ret, boxlen;
  314. static const char rmagic[] = "R6fnvWJ8";
  315. unsigned char *p, *box;
  316. unsigned char enonce[crypto_box_NONCEBYTES];
  317. struct rdns_curve_request *creq;
  318. struct rdns_resolver *resolver;
  319. resolver = ctx->resolver;
  320. ret = read (ioc->sock, buf, len);
  321. if (ret <= 0 || ret < 64) {
  322. /* Definitely not a DNSCurve packet */
  323. return ret;
  324. }
  325. if (memcmp (buf, rmagic, sizeof (rmagic) - 1) == 0) {
  326. /* Likely DNSCurve packet */
  327. p = ((unsigned char *)buf) + 8;
  328. HASH_FIND (hh, ctx->requests, p, 12, creq);
  329. if (creq == NULL) {
  330. rdns_info ("unable to find nonce in the internal hash");
  331. return ret;
  332. }
  333. memcpy (enonce, p, crypto_box_NONCEBYTES);
  334. p += crypto_box_NONCEBYTES;
  335. boxlen = ret - crypto_box_NONCEBYTES +
  336. crypto_box_BOXZEROBYTES -
  337. sizeof (rmagic) + 1;
  338. if (boxlen < 0) {
  339. return ret;
  340. }
  341. box = malloc (boxlen);
  342. sodium_memzero (box, crypto_box_BOXZEROBYTES);
  343. memcpy (box + crypto_box_BOXZEROBYTES, p,
  344. boxlen - crypto_box_BOXZEROBYTES);
  345. if (crypto_box_open_afternm (box, box, boxlen, enonce, creq->nm->k) != -1) {
  346. memcpy (buf, box + crypto_box_ZEROBYTES,
  347. boxlen - crypto_box_ZEROBYTES);
  348. ret = boxlen - crypto_box_ZEROBYTES;
  349. *req_out = creq->req;
  350. }
  351. else {
  352. rdns_info ("unable open cryptobox of size %d", (int)boxlen);
  353. }
  354. free (box);
  355. }
  356. return ret;
  357. }
  358. void
  359. rdns_curve_finish_request (struct rdns_request *req, void *plugin_data)
  360. {
  361. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  362. struct rdns_curve_request *creq = req->curve_plugin_data;
  363. if (creq != NULL) {
  364. REF_RELEASE (creq->key);
  365. HASH_DELETE (hh, ctx->requests, creq);
  366. }
  367. }
  368. void
  369. rdns_curve_dtor (struct rdns_resolver *resolver, void *plugin_data)
  370. {
  371. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  372. if (ctx->key_refresh_event != NULL) {
  373. resolver->async->del_periodic (resolver->async->data,
  374. ctx->key_refresh_event);
  375. }
  376. REF_RELEASE (ctx->cur_key);
  377. }
  378. #else
  379. /* Fake functions */
  380. struct rdns_curve_ctx* rdns_curve_ctx_new (double rekey_interval)
  381. {
  382. return NULL;
  383. }
  384. void rdns_curve_ctx_add_key (struct rdns_curve_ctx *ctx,
  385. const char *name, const unsigned char *pubkey)
  386. {
  387. }
  388. void rdns_curve_ctx_destroy (struct rdns_curve_ctx *ctx)
  389. {
  390. }
  391. void rdns_curve_register_plugin (struct rdns_resolver *resolver,
  392. struct rdns_curve_ctx *ctx)
  393. {
  394. }
  395. unsigned char *
  396. rdns_curve_key_from_hex (const char *hex)
  397. {
  398. return NULL;
  399. }
  400. #endif