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 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  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 <sys/socket.h>
  28. #include <unistd.h>
  29. #include "rdns.h"
  30. #include "dns_private.h"
  31. #include "rdns_curve.h"
  32. #include "ottery.h"
  33. #include "ref.h"
  34. #include "logger.h"
  35. #ifdef TWEETNACL
  36. #include <tweetnacl.h>
  37. void
  38. randombytes(uint8_t *data, uint64_t len)
  39. {
  40. ottery_rand_bytes (data, len);
  41. }
  42. void sodium_memzero (uint8_t *data, uint64_t len)
  43. {
  44. volatile uint8_t *p = data;
  45. while (len--) {
  46. *p = '\0';
  47. }
  48. }
  49. void sodium_init(void)
  50. {
  51. }
  52. ssize_t rdns_curve_send (struct rdns_request *req, void *plugin_data);
  53. ssize_t rdns_curve_recv (struct rdns_io_channel *ioc, void *buf, size_t len,
  54. void *plugin_data, struct rdns_request **req_out);
  55. void rdns_curve_finish_request (struct rdns_request *req, void *plugin_data);
  56. void rdns_curve_dtor (struct rdns_resolver *resolver, void *plugin_data);
  57. struct rdns_curve_entry {
  58. char *name;
  59. unsigned char pk[crypto_box_PUBLICKEYBYTES];
  60. UT_hash_handle hh;
  61. };
  62. struct rdns_curve_nm_entry {
  63. unsigned char k[crypto_box_BEFORENMBYTES];
  64. struct rdns_curve_entry *entry;
  65. struct rdns_curve_nm_entry *prev, *next;
  66. };
  67. struct rdns_curve_client_key {
  68. unsigned char pk[crypto_box_PUBLICKEYBYTES];
  69. unsigned char sk[crypto_box_SECRETKEYBYTES];
  70. struct rdns_curve_nm_entry *nms;
  71. uint64_t counter;
  72. unsigned int uses;
  73. ref_entry_t ref;
  74. };
  75. struct rdns_curve_request {
  76. struct rdns_request *req;
  77. struct rdns_curve_client_key *key;
  78. struct rdns_curve_entry *entry;
  79. struct rdns_curve_nm_entry *nm;
  80. unsigned char nonce[crypto_box_NONCEBYTES];
  81. UT_hash_handle hh;
  82. };
  83. struct rdns_curve_ctx {
  84. struct rdns_curve_entry *entries;
  85. struct rdns_curve_client_key *cur_key;
  86. struct rdns_curve_request *requests;
  87. double key_refresh_interval;
  88. void *key_refresh_event;
  89. struct rdns_resolver *resolver;
  90. };
  91. static struct rdns_curve_client_key *
  92. rdns_curve_client_key_new (struct rdns_curve_ctx *ctx)
  93. {
  94. struct rdns_curve_client_key *new;
  95. struct rdns_curve_nm_entry *nm;
  96. struct rdns_curve_entry *entry, *tmp;
  97. new = calloc (1, sizeof (struct rdns_curve_client_key));
  98. crypto_box_keypair (new->pk, new->sk);
  99. HASH_ITER (hh, ctx->entries, entry, tmp) {
  100. nm = calloc (1, sizeof (struct rdns_curve_nm_entry));
  101. nm->entry = entry;
  102. crypto_box_beforenm (nm->k, entry->pk, new->sk);
  103. DL_APPEND (new->nms, nm);
  104. }
  105. new->counter = ottery_rand_uint64 ();
  106. return new;
  107. }
  108. static struct rdns_curve_nm_entry *
  109. rdns_curve_find_nm (struct rdns_curve_client_key *key, struct rdns_curve_entry *entry)
  110. {
  111. struct rdns_curve_nm_entry *nm;
  112. DL_FOREACH (key->nms, nm) {
  113. if (nm->entry == entry) {
  114. return nm;
  115. }
  116. }
  117. return NULL;
  118. }
  119. static void
  120. rdns_curve_client_key_free (struct rdns_curve_client_key *key)
  121. {
  122. struct rdns_curve_nm_entry *nm, *tmp;
  123. DL_FOREACH_SAFE (key->nms, nm, tmp) {
  124. sodium_memzero (nm->k, sizeof (nm->k));
  125. free (nm);
  126. }
  127. sodium_memzero (key->sk, sizeof (key->sk));
  128. free (key);
  129. }
  130. struct rdns_curve_ctx*
  131. rdns_curve_ctx_new (double key_refresh_interval)
  132. {
  133. struct rdns_curve_ctx *new;
  134. new = calloc (1, sizeof (struct rdns_curve_ctx));
  135. new->key_refresh_interval = key_refresh_interval;
  136. return new;
  137. }
  138. void
  139. rdns_curve_ctx_add_key (struct rdns_curve_ctx *ctx,
  140. const char *name, const unsigned char *pubkey)
  141. {
  142. struct rdns_curve_entry *entry;
  143. bool success = true;
  144. entry = malloc (sizeof (struct rdns_curve_entry));
  145. if (entry != NULL) {
  146. entry->name = strdup (name);
  147. if (entry->name == NULL) {
  148. success = false;
  149. }
  150. memcpy (entry->pk, pubkey, sizeof (entry->pk));
  151. if (success) {
  152. HASH_ADD_KEYPTR (hh, ctx->entries, entry->name, strlen (entry->name), entry);
  153. }
  154. }
  155. }
  156. #define rdns_curve_write_hex(in, out, offset, base) do { \
  157. *(out) |= ((in)[(offset)] - (base)) << ((1 - offset) * 4); \
  158. } while (0)
  159. static bool
  160. rdns_curve_hex_to_byte (const char *in, unsigned char *out)
  161. {
  162. int i;
  163. for (i = 0; i <= 1; i ++) {
  164. if (in[i] >= '0' && in[i] <= '9') {
  165. rdns_curve_write_hex (in, out, i, '0');
  166. }
  167. else if (in[i] >= 'a' && in[i] <= 'f') {
  168. rdns_curve_write_hex (in, out, i, 'a' - 10);
  169. }
  170. else if (in[i] >= 'A' && in[i] <= 'F') {
  171. rdns_curve_write_hex (in, out, i, 'A' - 10);
  172. }
  173. else {
  174. return false;
  175. }
  176. }
  177. return true;
  178. }
  179. #undef rdns_curve_write_hex
  180. unsigned char *
  181. rdns_curve_key_from_hex (const char *hex)
  182. {
  183. unsigned int len = strlen (hex), i;
  184. unsigned char *res = NULL;
  185. if (len == crypto_box_PUBLICKEYBYTES * 2) {
  186. res = calloc (1, crypto_box_PUBLICKEYBYTES);
  187. for (i = 0; i < crypto_box_PUBLICKEYBYTES; i ++) {
  188. if (!rdns_curve_hex_to_byte (&hex[i * 2], &res[i])) {
  189. free (res);
  190. return NULL;
  191. }
  192. }
  193. }
  194. return res;
  195. }
  196. void
  197. rdns_curve_ctx_destroy (struct rdns_curve_ctx *ctx)
  198. {
  199. struct rdns_curve_entry *entry, *tmp;
  200. HASH_ITER (hh, ctx->entries, entry, tmp) {
  201. free (entry->name);
  202. free (entry);
  203. }
  204. free (ctx);
  205. }
  206. static void
  207. rdns_curve_refresh_key_callback (void *user_data)
  208. {
  209. struct rdns_curve_ctx *ctx = user_data;
  210. struct rdns_resolver *resolver;
  211. resolver = ctx->resolver;
  212. rdns_info ("refresh dnscurve keys");
  213. REF_RELEASE (ctx->cur_key);
  214. ctx->cur_key = rdns_curve_client_key_new (ctx);
  215. REF_INIT_RETAIN (ctx->cur_key, rdns_curve_client_key_free);
  216. }
  217. void
  218. rdns_curve_register_plugin (struct rdns_resolver *resolver,
  219. struct rdns_curve_ctx *ctx)
  220. {
  221. struct rdns_plugin *plugin;
  222. if (!resolver->async_binded) {
  223. return;
  224. }
  225. plugin = calloc (1, sizeof (struct rdns_plugin));
  226. if (plugin != NULL) {
  227. plugin->data = ctx;
  228. plugin->type = RDNS_PLUGIN_CURVE;
  229. plugin->cb.curve_plugin.send_cb = rdns_curve_send;
  230. plugin->cb.curve_plugin.recv_cb = rdns_curve_recv;
  231. plugin->cb.curve_plugin.finish_cb = rdns_curve_finish_request;
  232. plugin->dtor = rdns_curve_dtor;
  233. sodium_init ();
  234. ctx->cur_key = rdns_curve_client_key_new (ctx);
  235. REF_INIT_RETAIN (ctx->cur_key, rdns_curve_client_key_free);
  236. if (ctx->key_refresh_interval > 0) {
  237. ctx->key_refresh_event = resolver->async->add_periodic (
  238. resolver->async->data, ctx->key_refresh_interval,
  239. rdns_curve_refresh_key_callback, ctx);
  240. }
  241. ctx->resolver = resolver;
  242. rdns_resolver_register_plugin (resolver, plugin);
  243. }
  244. }
  245. ssize_t
  246. rdns_curve_send (struct rdns_request *req, void *plugin_data)
  247. {
  248. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  249. struct rdns_curve_entry *entry;
  250. struct iovec iov[4];
  251. unsigned char *m;
  252. static const char qmagic[] = "Q6fnvWj8";
  253. struct rdns_curve_request *creq;
  254. struct rdns_curve_nm_entry *nm;
  255. ssize_t ret, boxed_len;
  256. /* Check for key */
  257. HASH_FIND_STR (ctx->entries, req->io->srv->name, entry);
  258. if (entry != NULL) {
  259. nm = rdns_curve_find_nm (ctx->cur_key, entry);
  260. creq = malloc (sizeof (struct rdns_curve_request));
  261. if (creq == NULL) {
  262. return -1;
  263. }
  264. boxed_len = req->pos + crypto_box_ZEROBYTES;
  265. m = malloc (boxed_len);
  266. if (m == NULL) {
  267. return -1;
  268. }
  269. /* Ottery is faster than sodium native PRG that uses /dev/random only */
  270. memcpy (creq->nonce, &ctx->cur_key->counter, sizeof (uint64_t));
  271. ottery_rand_bytes (creq->nonce + sizeof (uint64_t), 12 - sizeof (uint64_t));
  272. sodium_memzero (creq->nonce + 12, crypto_box_NONCEBYTES - 12);
  273. sodium_memzero (m, crypto_box_ZEROBYTES);
  274. memcpy (m + crypto_box_ZEROBYTES, req->packet, req->pos);
  275. if (crypto_box_afternm (m, m, boxed_len,
  276. creq->nonce, nm->k) == -1) {
  277. sodium_memzero (m, boxed_len);
  278. free (m);
  279. return -1;
  280. }
  281. creq->key = ctx->cur_key;
  282. REF_RETAIN (ctx->cur_key);
  283. creq->entry = entry;
  284. creq->req = req;
  285. creq->nm = nm;
  286. HASH_ADD_KEYPTR (hh, ctx->requests, creq->nonce, 12, creq);
  287. req->curve_plugin_data = creq;
  288. ctx->cur_key->counter ++;
  289. ctx->cur_key->uses ++;
  290. /* Now form a dnscurve packet */
  291. iov[0].iov_base = (void *)qmagic;
  292. iov[0].iov_len = sizeof (qmagic) - 1;
  293. iov[1].iov_base = ctx->cur_key->pk;
  294. iov[1].iov_len = sizeof (ctx->cur_key->pk);
  295. iov[2].iov_base = creq->nonce;
  296. iov[2].iov_len = 12;
  297. iov[3].iov_base = m + crypto_box_BOXZEROBYTES;
  298. iov[3].iov_len = boxed_len - crypto_box_BOXZEROBYTES;
  299. ret = writev (req->io->sock, iov, sizeof (iov) / sizeof (iov[0]));
  300. sodium_memzero (m, boxed_len);
  301. free (m);
  302. }
  303. else {
  304. ret = write (req->io->sock, req->packet, req->pos);
  305. req->curve_plugin_data = NULL;
  306. }
  307. return ret;
  308. }
  309. ssize_t
  310. rdns_curve_recv (struct rdns_io_channel *ioc, void *buf, size_t len, void *plugin_data,
  311. struct rdns_request **req_out)
  312. {
  313. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  314. ssize_t ret, boxlen;
  315. static const char rmagic[] = "R6fnvWJ8";
  316. unsigned char *p, *box;
  317. unsigned char enonce[crypto_box_NONCEBYTES];
  318. struct rdns_curve_request *creq;
  319. struct rdns_resolver *resolver;
  320. resolver = ctx->resolver;
  321. ret = read (ioc->sock, buf, len);
  322. if (ret <= 0 || ret < 64) {
  323. /* Definitely not a DNSCurve packet */
  324. return ret;
  325. }
  326. if (memcmp (buf, rmagic, sizeof (rmagic) - 1) == 0) {
  327. /* Likely DNSCurve packet */
  328. p = ((unsigned char *)buf) + 8;
  329. HASH_FIND (hh, ctx->requests, p, 12, creq);
  330. if (creq == NULL) {
  331. rdns_info ("unable to find nonce in the internal hash");
  332. return ret;
  333. }
  334. memcpy (enonce, p, crypto_box_NONCEBYTES);
  335. p += crypto_box_NONCEBYTES;
  336. boxlen = ret - crypto_box_NONCEBYTES +
  337. crypto_box_BOXZEROBYTES -
  338. sizeof (rmagic) + 1;
  339. if (boxlen < 0) {
  340. return ret;
  341. }
  342. box = malloc (boxlen);
  343. sodium_memzero (box, crypto_box_BOXZEROBYTES);
  344. memcpy (box + crypto_box_BOXZEROBYTES, p,
  345. boxlen - crypto_box_BOXZEROBYTES);
  346. if (crypto_box_open_afternm (box, box, boxlen, enonce, creq->nm->k) != -1) {
  347. memcpy (buf, box + crypto_box_ZEROBYTES,
  348. boxlen - crypto_box_ZEROBYTES);
  349. ret = boxlen - crypto_box_ZEROBYTES;
  350. *req_out = creq->req;
  351. }
  352. else {
  353. rdns_info ("unable open cryptobox of size %d", (int)boxlen);
  354. }
  355. free (box);
  356. }
  357. return ret;
  358. }
  359. void
  360. rdns_curve_finish_request (struct rdns_request *req, void *plugin_data)
  361. {
  362. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  363. struct rdns_curve_request *creq = req->curve_plugin_data;
  364. if (creq != NULL) {
  365. REF_RELEASE (creq->key);
  366. HASH_DELETE (hh, ctx->requests, creq);
  367. }
  368. }
  369. void
  370. rdns_curve_dtor (struct rdns_resolver *resolver, void *plugin_data)
  371. {
  372. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  373. if (ctx->key_refresh_event != NULL) {
  374. resolver->async->del_periodic (resolver->async->data,
  375. ctx->key_refresh_event);
  376. }
  377. REF_RELEASE (ctx->cur_key);
  378. }
  379. #elif defined(USE_RSPAMD_CRYPTOBOX)
  380. #include "cryptobox.h"
  381. #ifndef crypto_box_ZEROBYTES
  382. #define crypto_box_ZEROBYTES 32
  383. #endif
  384. #ifndef crypto_box_BOXZEROBYTES
  385. #define crypto_box_BOXZEROBYTES 16
  386. #endif
  387. ssize_t rdns_curve_send (struct rdns_request *req, void *plugin_data,
  388. struct sockaddr *saddr, socklen_t slen);
  389. ssize_t rdns_curve_recv (struct rdns_io_channel *ioc, void *buf, size_t len,
  390. void *plugin_data, struct rdns_request **req_out,
  391. struct sockaddr *saddr, socklen_t slen);
  392. void rdns_curve_finish_request (struct rdns_request *req, void *plugin_data);
  393. void rdns_curve_dtor (struct rdns_resolver *resolver, void *plugin_data);
  394. struct rdns_curve_entry {
  395. char *name;
  396. rspamd_pk_t pk;
  397. UT_hash_handle hh;
  398. };
  399. struct rdns_curve_nm_entry {
  400. rspamd_nm_t k;
  401. struct rdns_curve_entry *entry;
  402. struct rdns_curve_nm_entry *prev, *next;
  403. };
  404. struct rdns_curve_client_key {
  405. rspamd_pk_t pk;
  406. rspamd_sk_t sk;
  407. struct rdns_curve_nm_entry *nms;
  408. uint64_t counter;
  409. unsigned int uses;
  410. ref_entry_t ref;
  411. };
  412. struct rdns_curve_request {
  413. struct rdns_request *req;
  414. struct rdns_curve_client_key *key;
  415. struct rdns_curve_entry *entry;
  416. struct rdns_curve_nm_entry *nm;
  417. rspamd_nonce_t nonce;
  418. UT_hash_handle hh;
  419. };
  420. struct rdns_curve_ctx {
  421. struct rdns_curve_entry *entries;
  422. struct rdns_curve_client_key *cur_key;
  423. struct rdns_curve_request *requests;
  424. double key_refresh_interval;
  425. void *key_refresh_event;
  426. struct rdns_resolver *resolver;
  427. };
  428. static struct rdns_curve_client_key *
  429. rdns_curve_client_key_new (struct rdns_curve_ctx *ctx)
  430. {
  431. struct rdns_curve_client_key *new;
  432. struct rdns_curve_nm_entry *nm;
  433. struct rdns_curve_entry *entry, *tmp;
  434. new = calloc (1, sizeof (struct rdns_curve_client_key));
  435. rspamd_cryptobox_keypair (new->pk, new->sk, RSPAMD_CRYPTOBOX_MODE_25519);
  436. HASH_ITER (hh, ctx->entries, entry, tmp) {
  437. nm = calloc (1, sizeof (struct rdns_curve_nm_entry));
  438. nm->entry = entry;
  439. rspamd_cryptobox_nm (nm->k, entry->pk, new->sk,
  440. RSPAMD_CRYPTOBOX_MODE_25519);
  441. DL_APPEND (new->nms, nm);
  442. }
  443. new->counter = ottery_rand_uint64 ();
  444. return new;
  445. }
  446. static struct rdns_curve_nm_entry *
  447. rdns_curve_find_nm (struct rdns_curve_client_key *key, struct rdns_curve_entry *entry)
  448. {
  449. struct rdns_curve_nm_entry *nm;
  450. DL_FOREACH (key->nms, nm) {
  451. if (nm->entry == entry) {
  452. return nm;
  453. }
  454. }
  455. return NULL;
  456. }
  457. static void
  458. rdns_curve_client_key_free (struct rdns_curve_client_key *key)
  459. {
  460. struct rdns_curve_nm_entry *nm, *tmp;
  461. DL_FOREACH_SAFE (key->nms, nm, tmp) {
  462. rspamd_explicit_memzero (nm->k, sizeof (nm->k));
  463. free (nm);
  464. }
  465. rspamd_explicit_memzero (key->sk, sizeof (key->sk));
  466. free (key);
  467. }
  468. struct rdns_curve_ctx*
  469. rdns_curve_ctx_new (double key_refresh_interval)
  470. {
  471. struct rdns_curve_ctx *new;
  472. new = calloc (1, sizeof (struct rdns_curve_ctx));
  473. new->key_refresh_interval = key_refresh_interval;
  474. return new;
  475. }
  476. void
  477. rdns_curve_ctx_add_key (struct rdns_curve_ctx *ctx,
  478. const char *name, const unsigned char *pubkey)
  479. {
  480. struct rdns_curve_entry *entry;
  481. bool success = true;
  482. entry = malloc (sizeof (struct rdns_curve_entry));
  483. if (entry != NULL) {
  484. entry->name = strdup (name);
  485. if (entry->name == NULL) {
  486. success = false;
  487. }
  488. memcpy (entry->pk, pubkey, sizeof (entry->pk));
  489. if (success) {
  490. HASH_ADD_KEYPTR (hh, ctx->entries, entry->name, strlen (entry->name), entry);
  491. }
  492. }
  493. }
  494. #define rdns_curve_write_hex(in, out, offset, base) do { \
  495. *(out) |= ((in)[(offset)] - (base)) << ((1 - offset) * 4); \
  496. } while (0)
  497. static bool
  498. rdns_curve_hex_to_byte (const char *in, unsigned char *out)
  499. {
  500. int i;
  501. for (i = 0; i <= 1; i ++) {
  502. if (in[i] >= '0' && in[i] <= '9') {
  503. rdns_curve_write_hex (in, out, i, '0');
  504. }
  505. else if (in[i] >= 'a' && in[i] <= 'f') {
  506. rdns_curve_write_hex (in, out, i, 'a' - 10);
  507. }
  508. else if (in[i] >= 'A' && in[i] <= 'F') {
  509. rdns_curve_write_hex (in, out, i, 'A' - 10);
  510. }
  511. else {
  512. return false;
  513. }
  514. }
  515. return true;
  516. }
  517. #undef rdns_curve_write_hex
  518. unsigned char *
  519. rdns_curve_key_from_hex (const char *hex)
  520. {
  521. unsigned int len = strlen (hex), i;
  522. unsigned char *res = NULL;
  523. if (len == rspamd_cryptobox_pk_bytes (RSPAMD_CRYPTOBOX_MODE_25519) * 2) {
  524. res = calloc (1, rspamd_cryptobox_pk_bytes (RSPAMD_CRYPTOBOX_MODE_25519));
  525. for (i = 0;
  526. i < rspamd_cryptobox_pk_bytes (RSPAMD_CRYPTOBOX_MODE_25519);
  527. i ++) {
  528. if (!rdns_curve_hex_to_byte (&hex[i * 2], &res[i])) {
  529. free (res);
  530. return NULL;
  531. }
  532. }
  533. }
  534. return res;
  535. }
  536. void
  537. rdns_curve_ctx_destroy (struct rdns_curve_ctx *ctx)
  538. {
  539. struct rdns_curve_entry *entry, *tmp;
  540. HASH_ITER (hh, ctx->entries, entry, tmp) {
  541. free (entry->name);
  542. free (entry);
  543. }
  544. free (ctx);
  545. }
  546. static void
  547. rdns_curve_refresh_key_callback (void *user_data)
  548. {
  549. struct rdns_curve_ctx *ctx = user_data;
  550. struct rdns_resolver *resolver;
  551. resolver = ctx->resolver;
  552. rdns_info ("refresh dnscurve keys");
  553. REF_RELEASE (ctx->cur_key);
  554. ctx->cur_key = rdns_curve_client_key_new (ctx);
  555. REF_INIT_RETAIN (ctx->cur_key, rdns_curve_client_key_free);
  556. }
  557. void
  558. rdns_curve_register_plugin (struct rdns_resolver *resolver,
  559. struct rdns_curve_ctx *ctx)
  560. {
  561. struct rdns_plugin *plugin;
  562. if (!resolver->async_binded) {
  563. return;
  564. }
  565. plugin = calloc (1, sizeof (struct rdns_plugin));
  566. if (plugin != NULL) {
  567. plugin->data = ctx;
  568. plugin->type = RDNS_PLUGIN_CURVE;
  569. plugin->cb.curve_plugin.send_cb = rdns_curve_send;
  570. plugin->cb.curve_plugin.recv_cb = rdns_curve_recv;
  571. plugin->cb.curve_plugin.finish_cb = rdns_curve_finish_request;
  572. plugin->dtor = rdns_curve_dtor;
  573. ctx->cur_key = rdns_curve_client_key_new (ctx);
  574. REF_INIT_RETAIN (ctx->cur_key, rdns_curve_client_key_free);
  575. if (ctx->key_refresh_interval > 0) {
  576. ctx->key_refresh_event = resolver->async->add_periodic (
  577. resolver->async->data, ctx->key_refresh_interval,
  578. rdns_curve_refresh_key_callback, ctx);
  579. }
  580. ctx->resolver = resolver;
  581. rdns_resolver_register_plugin (resolver, plugin);
  582. }
  583. }
  584. ssize_t
  585. rdns_curve_send (struct rdns_request *req, void *plugin_data,
  586. struct sockaddr *saddr, socklen_t slen)
  587. {
  588. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  589. struct rdns_curve_entry *entry;
  590. struct iovec iov[4];
  591. unsigned char *m;
  592. static const char qmagic[] = "Q6fnvWj8";
  593. struct rdns_curve_request *creq;
  594. struct rdns_curve_nm_entry *nm;
  595. ssize_t ret, boxed_len;
  596. /* Check for key */
  597. HASH_FIND_STR (ctx->entries, req->io->srv->name, entry);
  598. if (entry != NULL) {
  599. nm = rdns_curve_find_nm (ctx->cur_key, entry);
  600. creq = malloc (sizeof (struct rdns_curve_request));
  601. if (creq == NULL) {
  602. return -1;
  603. }
  604. boxed_len = req->pos + crypto_box_ZEROBYTES;
  605. m = malloc (boxed_len);
  606. if (m == NULL) {
  607. free(creq);
  608. return -1;
  609. }
  610. /* Ottery is faster than sodium native PRG that uses /dev/random only */
  611. memcpy (creq->nonce, &ctx->cur_key->counter, sizeof (uint64_t));
  612. ottery_rand_bytes (creq->nonce + sizeof (uint64_t), 12 - sizeof (uint64_t));
  613. rspamd_explicit_memzero (creq->nonce + 12,
  614. rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519) - 12);
  615. rspamd_explicit_memzero (m, crypto_box_ZEROBYTES);
  616. memcpy (m + crypto_box_ZEROBYTES, req->packet, req->pos);
  617. rspamd_cryptobox_encrypt_nm_inplace (m + crypto_box_ZEROBYTES,
  618. boxed_len,
  619. creq->nonce,
  620. nm->k,
  621. m,
  622. RSPAMD_CRYPTOBOX_MODE_25519);
  623. creq->key = ctx->cur_key;
  624. REF_RETAIN (ctx->cur_key);
  625. creq->entry = entry;
  626. creq->req = req;
  627. creq->nm = nm;
  628. HASH_ADD_KEYPTR (hh, ctx->requests, creq->nonce, 12, creq);
  629. req->curve_plugin_data = creq;
  630. ctx->cur_key->counter ++;
  631. ctx->cur_key->uses ++;
  632. /* Now form a dnscurve packet */
  633. iov[0].iov_base = (void *)qmagic;
  634. iov[0].iov_len = sizeof (qmagic) - 1;
  635. iov[1].iov_base = ctx->cur_key->pk;
  636. iov[1].iov_len = sizeof (ctx->cur_key->pk);
  637. iov[2].iov_base = creq->nonce;
  638. iov[2].iov_len = 12;
  639. iov[3].iov_base = m + crypto_box_BOXZEROBYTES;
  640. iov[3].iov_len = boxed_len - crypto_box_BOXZEROBYTES;
  641. struct msghdr msg;
  642. memset (&msg, 0, sizeof (msg));
  643. msg.msg_namelen = slen;
  644. msg.msg_name = saddr;
  645. msg.msg_iov = iov;
  646. msg.msg_iovlen = sizeof (iov) / sizeof (iov[0]);
  647. ret = sendmsg (req->io->sock, &msg, 0);
  648. rspamd_explicit_memzero (m, boxed_len);
  649. free (m);
  650. }
  651. else {
  652. ret = sendto (req->io->sock, req->packet, req->pos, 0, saddr, slen);
  653. req->curve_plugin_data = NULL;
  654. }
  655. return ret;
  656. }
  657. ssize_t
  658. rdns_curve_recv (struct rdns_io_channel *ioc, void *buf, size_t len, void *plugin_data,
  659. struct rdns_request **req_out, struct sockaddr *saddr, socklen_t slen)
  660. {
  661. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  662. ssize_t ret, boxlen;
  663. static const char rmagic[] = "R6fnvWJ8";
  664. unsigned char *p, *box;
  665. unsigned char enonce[24];
  666. struct rdns_curve_request *creq;
  667. struct rdns_resolver *resolver;
  668. resolver = ctx->resolver;
  669. ret = recv (ioc->sock, buf, len, 0);
  670. if (ret <= 0 || ret < 64) {
  671. /* Definitely not a DNSCurve packet */
  672. return ret;
  673. }
  674. if (memcmp (buf, rmagic, sizeof (rmagic) - 1) == 0) {
  675. /* Likely DNSCurve packet */
  676. p = ((unsigned char *)buf) + 8;
  677. HASH_FIND (hh, ctx->requests, p, 12, creq);
  678. if (creq == NULL) {
  679. rdns_info ("unable to find nonce in the internal hash");
  680. return ret;
  681. }
  682. memcpy (enonce, p, rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519));
  683. p += rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519);
  684. boxlen = ret - rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
  685. crypto_box_BOXZEROBYTES -
  686. sizeof (rmagic) + 1;
  687. if (boxlen < 0) {
  688. return ret;
  689. }
  690. box = malloc (boxlen);
  691. rspamd_explicit_memzero (box, crypto_box_BOXZEROBYTES);
  692. memcpy (box + crypto_box_BOXZEROBYTES, p,
  693. boxlen - crypto_box_BOXZEROBYTES);
  694. if (!rspamd_cryptobox_decrypt_nm_inplace (
  695. box + rspamd_cryptobox_mac_bytes (RSPAMD_CRYPTOBOX_MODE_25519),
  696. boxlen - rspamd_cryptobox_mac_bytes (RSPAMD_CRYPTOBOX_MODE_25519),
  697. enonce, creq->nm->k, box, RSPAMD_CRYPTOBOX_MODE_25519)) {
  698. memcpy (buf, box + crypto_box_ZEROBYTES,
  699. boxlen - crypto_box_ZEROBYTES);
  700. ret = boxlen - crypto_box_ZEROBYTES;
  701. *req_out = creq->req;
  702. }
  703. else {
  704. rdns_info ("unable open cryptobox of size %d", (int)boxlen);
  705. }
  706. free (box);
  707. }
  708. return ret;
  709. }
  710. void
  711. rdns_curve_finish_request (struct rdns_request *req, void *plugin_data)
  712. {
  713. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  714. struct rdns_curve_request *creq = req->curve_plugin_data;
  715. if (creq != NULL) {
  716. REF_RELEASE (creq->key);
  717. HASH_DELETE (hh, ctx->requests, creq);
  718. }
  719. }
  720. void
  721. rdns_curve_dtor (struct rdns_resolver *resolver, void *plugin_data)
  722. {
  723. struct rdns_curve_ctx *ctx = (struct rdns_curve_ctx *)plugin_data;
  724. if (ctx->key_refresh_event != NULL) {
  725. resolver->async->del_periodic (resolver->async->data,
  726. ctx->key_refresh_event);
  727. }
  728. REF_RELEASE (ctx->cur_key);
  729. }
  730. #else
  731. /* Fake functions */
  732. struct rdns_curve_ctx* rdns_curve_ctx_new (double rekey_interval)
  733. {
  734. return NULL;
  735. }
  736. void rdns_curve_ctx_add_key (struct rdns_curve_ctx *ctx,
  737. const char *name, const unsigned char *pubkey)
  738. {
  739. }
  740. void rdns_curve_ctx_destroy (struct rdns_curve_ctx *ctx)
  741. {
  742. }
  743. void rdns_curve_register_plugin (struct rdns_resolver *resolver,
  744. struct rdns_curve_ctx *ctx)
  745. {
  746. }
  747. unsigned char *
  748. rdns_curve_key_from_hex (const char *hex)
  749. {
  750. return NULL;
  751. }
  752. #endif