kex_fuzz.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. // libfuzzer driver for key exchange fuzzing.
  2. #include <sys/types.h>
  3. #include <sys/param.h>
  4. #include <stdio.h>
  5. #include <stdint.h>
  6. #include <stdlib.h>
  7. #include <string.h>
  8. extern "C" {
  9. #include "includes.h"
  10. #include "ssherr.h"
  11. #include "ssh_api.h"
  12. #include "sshbuf.h"
  13. #include "packet.h"
  14. #include "myproposal.h"
  15. #include "xmalloc.h"
  16. #include "authfile.h"
  17. #include "log.h"
  18. #include "fixed-keys.h"
  19. // Define if you want to generate traces.
  20. /* #define STANDALONE 1 */
  21. static int prepare_key(struct shared_state *st, int keytype, int bits);
  22. struct shared_state {
  23. size_t nkeys;
  24. struct sshkey **privkeys, **pubkeys;
  25. };
  26. struct test_state {
  27. struct sshbuf *smsgs, *cmsgs; /* output, for standalone mode */
  28. struct sshbuf *sin, *cin; /* input; setup per-test in do_kex_with_key */
  29. struct sshbuf *s_template, *c_template; /* main copy of input */
  30. };
  31. static int
  32. do_send_and_receive(struct ssh *from, struct ssh *to,
  33. struct sshbuf *store, int clobber, size_t *n)
  34. {
  35. u_char type;
  36. size_t len;
  37. const u_char *buf;
  38. int r;
  39. for (*n = 0;; (*n)++) {
  40. if ((r = ssh_packet_next(from, &type)) != 0) {
  41. debug_fr(r, "ssh_packet_next");
  42. return r;
  43. }
  44. if (type != 0)
  45. return 0;
  46. buf = ssh_output_ptr(from, &len);
  47. debug("%zu%s", len, clobber ? " ignore" : "");
  48. if (len == 0)
  49. return 0;
  50. if ((r = ssh_output_consume(from, len)) != 0) {
  51. debug_fr(r, "ssh_output_consume");
  52. return r;
  53. }
  54. if (store != NULL && (r = sshbuf_put(store, buf, len)) != 0) {
  55. debug_fr(r, "sshbuf_put");
  56. return r;
  57. }
  58. if (!clobber && (r = ssh_input_append(to, buf, len)) != 0) {
  59. debug_fr(r, "ssh_input_append");
  60. return r;
  61. }
  62. }
  63. }
  64. static int
  65. run_kex(struct test_state *ts, struct ssh *client, struct ssh *server)
  66. {
  67. int r = 0;
  68. size_t cn, sn;
  69. /* If fuzzing, replace server/client input */
  70. if (ts->sin != NULL) {
  71. if ((r = ssh_input_append(server, sshbuf_ptr(ts->sin),
  72. sshbuf_len(ts->sin))) != 0) {
  73. error_fr(r, "ssh_input_append");
  74. return r;
  75. }
  76. sshbuf_reset(ts->sin);
  77. }
  78. if (ts->cin != NULL) {
  79. if ((r = ssh_input_append(client, sshbuf_ptr(ts->cin),
  80. sshbuf_len(ts->cin))) != 0) {
  81. error_fr(r, "ssh_input_append");
  82. return r;
  83. }
  84. sshbuf_reset(ts->cin);
  85. }
  86. while (!server->kex->done || !client->kex->done) {
  87. cn = sn = 0;
  88. debug("S:");
  89. if ((r = do_send_and_receive(server, client,
  90. ts->smsgs, ts->cin != NULL, &sn)) != 0) {
  91. debug_fr(r, "S->C");
  92. break;
  93. }
  94. debug("C:");
  95. if ((r = do_send_and_receive(client, server,
  96. ts->cmsgs, ts->sin != NULL, &cn)) != 0) {
  97. debug_fr(r, "C->S");
  98. break;
  99. }
  100. if (cn == 0 && sn == 0) {
  101. debug("kex stalled");
  102. r = SSH_ERR_PROTOCOL_ERROR;
  103. break;
  104. }
  105. }
  106. debug_fr(r, "done");
  107. return r;
  108. }
  109. static void
  110. store_key(struct shared_state *st, struct sshkey *pubkey,
  111. struct sshkey *privkey)
  112. {
  113. if (st == NULL || pubkey->type < 0 || pubkey->type > INT_MAX ||
  114. privkey->type != pubkey->type ||
  115. ((size_t)pubkey->type < st->nkeys &&
  116. st->pubkeys[pubkey->type] != NULL))
  117. abort();
  118. if ((size_t)pubkey->type >= st->nkeys) {
  119. st->pubkeys = (struct sshkey **)xrecallocarray(st->pubkeys,
  120. st->nkeys, pubkey->type + 1, sizeof(*st->pubkeys));
  121. st->privkeys = (struct sshkey **)xrecallocarray(st->privkeys,
  122. st->nkeys, privkey->type + 1, sizeof(*st->privkeys));
  123. st->nkeys = privkey->type + 1;
  124. }
  125. debug("store %s at %d", sshkey_ssh_name(pubkey), pubkey->type);
  126. st->pubkeys[pubkey->type] = pubkey;
  127. st->privkeys[privkey->type] = privkey;
  128. }
  129. static int
  130. prepare_keys(struct shared_state *st)
  131. {
  132. if (prepare_key(st, KEY_RSA, 2048) != 0 ||
  133. prepare_key(st, KEY_DSA, 1024) != 0 ||
  134. prepare_key(st, KEY_ECDSA, 256) != 0 ||
  135. prepare_key(st, KEY_ED25519, 256) != 0) {
  136. error_f("key prepare failed");
  137. return -1;
  138. }
  139. return 0;
  140. }
  141. static struct sshkey *
  142. get_pubkey(struct shared_state *st, int keytype)
  143. {
  144. if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys ||
  145. st->pubkeys == NULL || st->pubkeys[keytype] == NULL)
  146. abort();
  147. return st->pubkeys[keytype];
  148. }
  149. static struct sshkey *
  150. get_privkey(struct shared_state *st, int keytype)
  151. {
  152. if (st == NULL || keytype < 0 || (size_t)keytype >= st->nkeys ||
  153. st->privkeys == NULL || st->privkeys[keytype] == NULL)
  154. abort();
  155. return st->privkeys[keytype];
  156. }
  157. static int
  158. do_kex_with_key(struct shared_state *st, struct test_state *ts,
  159. const char *kex, int keytype)
  160. {
  161. struct ssh *client = NULL, *server = NULL;
  162. struct sshkey *privkey = NULL, *pubkey = NULL;
  163. struct sshbuf *state = NULL;
  164. struct kex_params kex_params;
  165. const char *ccp, *proposal[PROPOSAL_MAX] = { KEX_CLIENT };
  166. char *myproposal[PROPOSAL_MAX] = {0}, *keyname = NULL;
  167. int i, r;
  168. ts->cin = ts->sin = NULL;
  169. if (ts->c_template != NULL &&
  170. (ts->cin = sshbuf_fromb(ts->c_template)) == NULL)
  171. abort();
  172. if (ts->s_template != NULL &&
  173. (ts->sin = sshbuf_fromb(ts->s_template)) == NULL)
  174. abort();
  175. pubkey = get_pubkey(st, keytype);
  176. privkey = get_privkey(st, keytype);
  177. keyname = xstrdup(sshkey_ssh_name(privkey));
  178. if (ts->cin != NULL) {
  179. debug("%s %s clobber client %zu", kex, keyname,
  180. sshbuf_len(ts->cin));
  181. } else if (ts->sin != NULL) {
  182. debug("%s %s clobber server %zu", kex, keyname,
  183. sshbuf_len(ts->sin));
  184. } else
  185. debug("%s %s noclobber", kex, keyname);
  186. for (i = 0; i < PROPOSAL_MAX; i++) {
  187. ccp = proposal[i];
  188. #ifdef CIPHER_NONE_AVAIL
  189. if (i == PROPOSAL_ENC_ALGS_CTOS || i == PROPOSAL_ENC_ALGS_STOC)
  190. ccp = "none";
  191. #endif
  192. if (i == PROPOSAL_SERVER_HOST_KEY_ALGS)
  193. ccp = keyname;
  194. else if (i == PROPOSAL_KEX_ALGS && kex != NULL)
  195. ccp = kex;
  196. if ((myproposal[i] = strdup(ccp)) == NULL) {
  197. error_f("strdup prop %d", i);
  198. goto fail;
  199. }
  200. }
  201. memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
  202. if ((r = ssh_init(&client, 0, &kex_params)) != 0) {
  203. error_fr(r, "init client");
  204. goto fail;
  205. }
  206. if ((r = ssh_init(&server, 1, &kex_params)) != 0) {
  207. error_fr(r, "init server");
  208. goto fail;
  209. }
  210. if ((r = ssh_add_hostkey(server, privkey)) != 0 ||
  211. (r = ssh_add_hostkey(client, pubkey)) != 0) {
  212. error_fr(r, "add hostkeys");
  213. goto fail;
  214. }
  215. if ((r = run_kex(ts, client, server)) != 0) {
  216. error_fr(r, "kex");
  217. goto fail;
  218. }
  219. /* XXX rekex, set_state, etc */
  220. fail:
  221. for (i = 0; i < PROPOSAL_MAX; i++)
  222. free(myproposal[i]);
  223. sshbuf_free(ts->sin);
  224. sshbuf_free(ts->cin);
  225. sshbuf_free(state);
  226. ssh_free(client);
  227. ssh_free(server);
  228. free(keyname);
  229. return r;
  230. }
  231. static int
  232. prepare_key(struct shared_state *st, int kt, int bits)
  233. {
  234. const char *pubstr = NULL;
  235. const char *privstr = NULL;
  236. char *tmp, *cp;
  237. struct sshkey *privkey = NULL, *pubkey = NULL;
  238. struct sshbuf *b = NULL;
  239. int r;
  240. switch (kt) {
  241. case KEY_RSA:
  242. pubstr = PUB_RSA;
  243. privstr = PRIV_RSA;
  244. break;
  245. case KEY_DSA:
  246. pubstr = PUB_DSA;
  247. privstr = PRIV_DSA;
  248. break;
  249. case KEY_ECDSA:
  250. pubstr = PUB_ECDSA;
  251. privstr = PRIV_ECDSA;
  252. break;
  253. case KEY_ED25519:
  254. pubstr = PUB_ED25519;
  255. privstr = PRIV_ED25519;
  256. break;
  257. default:
  258. abort();
  259. }
  260. if ((b = sshbuf_from(privstr, strlen(privstr))) == NULL)
  261. abort();
  262. if ((r = sshkey_parse_private_fileblob(b, "", &privkey, NULL)) != 0) {
  263. error_fr(r, "priv %d", kt);
  264. abort();
  265. }
  266. sshbuf_free(b);
  267. tmp = cp = xstrdup(pubstr);
  268. if ((pubkey = sshkey_new(KEY_UNSPEC)) == NULL)
  269. abort();
  270. if ((r = sshkey_read(pubkey, &cp)) != 0) {
  271. error_fr(r, "pub %d", kt);
  272. abort();
  273. }
  274. free(tmp);
  275. store_key(st, pubkey, privkey);
  276. return 0;
  277. }
  278. #if defined(STANDALONE)
  279. #if 0 /* use this if generating new keys to embed above */
  280. static int
  281. prepare_key(struct shared_state *st, int keytype, int bits)
  282. {
  283. struct sshkey *privkey = NULL, *pubkey = NULL;
  284. int r;
  285. if ((r = sshkey_generate(keytype, bits, &privkey)) != 0) {
  286. error_fr(r, "generate");
  287. abort();
  288. }
  289. if ((r = sshkey_from_private(privkey, &pubkey)) != 0) {
  290. error_fr(r, "make pubkey");
  291. abort();
  292. }
  293. store_key(st, pubkey, privkey);
  294. return 0;
  295. }
  296. #endif
  297. int main(void)
  298. {
  299. static struct shared_state *st;
  300. struct test_state *ts;
  301. const int keytypes[] = { KEY_RSA, KEY_DSA, KEY_ECDSA, KEY_ED25519, -1 };
  302. const char *kextypes[] = {
  303. "sntrup761x25519-sha512@openssh.com",
  304. "curve25519-sha256@libssh.org",
  305. "ecdh-sha2-nistp256",
  306. "diffie-hellman-group1-sha1",
  307. "diffie-hellman-group-exchange-sha1",
  308. NULL,
  309. };
  310. int i, j;
  311. char *path;
  312. FILE *f;
  313. log_init("kex_fuzz", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
  314. if (st == NULL) {
  315. st = (struct shared_state *)xcalloc(1, sizeof(*st));
  316. prepare_keys(st);
  317. }
  318. /* Run each kex method for each key and save client/server packets */
  319. for (i = 0; keytypes[i] != -1; i++) {
  320. for (j = 0; kextypes[j] != NULL; j++) {
  321. ts = (struct test_state *)xcalloc(1, sizeof(*ts));
  322. ts->smsgs = sshbuf_new();
  323. ts->cmsgs = sshbuf_new();
  324. do_kex_with_key(st, ts, kextypes[j], keytypes[i]);
  325. xasprintf(&path, "S2C-%s-%s",
  326. kextypes[j], sshkey_type(st->pubkeys[keytypes[i]]));
  327. debug("%s", path);
  328. if ((f = fopen(path, "wb+")) == NULL)
  329. abort();
  330. if (fwrite(sshbuf_ptr(ts->smsgs), 1,
  331. sshbuf_len(ts->smsgs), f) != sshbuf_len(ts->smsgs))
  332. abort();
  333. fclose(f);
  334. free(path);
  335. //sshbuf_dump(ts->smsgs, stderr);
  336. xasprintf(&path, "C2S-%s-%s",
  337. kextypes[j], sshkey_type(st->pubkeys[keytypes[i]]));
  338. debug("%s", path);
  339. if ((f = fopen(path, "wb+")) == NULL)
  340. abort();
  341. if (fwrite(sshbuf_ptr(ts->cmsgs), 1,
  342. sshbuf_len(ts->cmsgs), f) != sshbuf_len(ts->cmsgs))
  343. abort();
  344. fclose(f);
  345. free(path);
  346. //sshbuf_dump(ts->cmsgs, stderr);
  347. sshbuf_free(ts->smsgs);
  348. sshbuf_free(ts->cmsgs);
  349. free(ts);
  350. }
  351. }
  352. for (i = 0; keytypes[i] != -1; i++) {
  353. xasprintf(&path, "%s.priv",
  354. sshkey_type(st->privkeys[keytypes[i]]));
  355. debug("%s", path);
  356. if (sshkey_save_private(st->privkeys[keytypes[i]], path,
  357. "", "", SSHKEY_PRIVATE_OPENSSH, NULL, 0) != 0)
  358. abort();
  359. free(path);
  360. xasprintf(&path, "%s.pub",
  361. sshkey_type(st->pubkeys[keytypes[i]]));
  362. debug("%s", path);
  363. if (sshkey_save_public(st->pubkeys[keytypes[i]], path, "") != 0)
  364. abort();
  365. free(path);
  366. }
  367. }
  368. #else /* !STANDALONE */
  369. static void
  370. do_kex(struct shared_state *st, struct test_state *ts, const char *kex)
  371. {
  372. do_kex_with_key(st, ts, kex, KEY_RSA);
  373. do_kex_with_key(st, ts, kex, KEY_DSA);
  374. do_kex_with_key(st, ts, kex, KEY_ECDSA);
  375. do_kex_with_key(st, ts, kex, KEY_ED25519);
  376. }
  377. static void
  378. kex_tests(struct shared_state *st, struct test_state *ts)
  379. {
  380. do_kex(st, ts, "sntrup4591761x25519-sha512@tinyssh.org");
  381. do_kex(st, ts, "curve25519-sha256@libssh.org");
  382. do_kex(st, ts, "ecdh-sha2-nistp256");
  383. do_kex(st, ts, "diffie-hellman-group1-sha1");
  384. do_kex(st, ts, "diffie-hellman-group-exchange-sha1");
  385. }
  386. int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
  387. {
  388. static struct shared_state *st;
  389. struct test_state *ts;
  390. u_char crbuf[SSH_MAX_PRE_BANNER_LINES * 4];
  391. u_char zbuf[4096] = {0};
  392. static LogLevel loglevel = SYSLOG_LEVEL_INFO;
  393. if (st == NULL) {
  394. if (getenv("DEBUG") != NULL || getenv("KEX_FUZZ_DEBUG") != NULL)
  395. loglevel = SYSLOG_LEVEL_DEBUG3;
  396. log_init("kex_fuzz",
  397. loglevel, SYSLOG_FACILITY_AUTH, 1);
  398. st = (struct shared_state *)xcalloc(1, sizeof(*st));
  399. prepare_keys(st);
  400. }
  401. /* Ensure that we can complete (fail) banner exchange at least */
  402. memset(crbuf, '\n', sizeof(crbuf));
  403. ts = (struct test_state *)xcalloc(1, sizeof(*ts));
  404. if ((ts->s_template = sshbuf_new()) == NULL ||
  405. sshbuf_put(ts->s_template, data, size) != 0 ||
  406. sshbuf_put(ts->s_template, crbuf, sizeof(crbuf)) != 0 ||
  407. sshbuf_put(ts->s_template, zbuf, sizeof(zbuf)) != 0)
  408. abort();
  409. kex_tests(st, ts);
  410. sshbuf_free(ts->s_template);
  411. free(ts);
  412. ts = (struct test_state *)xcalloc(1, sizeof(*ts));
  413. if ((ts->c_template = sshbuf_new()) == NULL ||
  414. sshbuf_put(ts->c_template, data, size) != 0 ||
  415. sshbuf_put(ts->c_template, crbuf, sizeof(crbuf)) != 0 ||
  416. sshbuf_put(ts->c_template, zbuf, sizeof(zbuf)) != 0)
  417. abort();
  418. kex_tests(st, ts);
  419. sshbuf_free(ts->c_template);
  420. free(ts);
  421. return 0;
  422. }
  423. #endif /* STANDALONE */
  424. } /* extern "C" */