sshkey-xmss.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. /* $OpenBSD: sshkey-xmss.c,v 1.8 2019/11/13 07:53:10 markus Exp $ */
  2. /*
  3. * Copyright (c) 2017 Markus Friedl. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. 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 THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "includes.h"
  26. #ifdef WITH_XMSS
  27. #include <sys/types.h>
  28. #include <sys/uio.h>
  29. #include <stdio.h>
  30. #include <string.h>
  31. #include <unistd.h>
  32. #include <fcntl.h>
  33. #include <errno.h>
  34. #ifdef HAVE_SYS_FILE_H
  35. # include <sys/file.h>
  36. #endif
  37. #include "ssh2.h"
  38. #include "ssherr.h"
  39. #include "sshbuf.h"
  40. #include "cipher.h"
  41. #include "sshkey.h"
  42. #include "sshkey-xmss.h"
  43. #include "atomicio.h"
  44. #include "xmss_fast.h"
  45. /* opaque internal XMSS state */
  46. #define XMSS_MAGIC "xmss-state-v1"
  47. #define XMSS_CIPHERNAME "aes256-gcm@openssh.com"
  48. struct ssh_xmss_state {
  49. xmss_params params;
  50. u_int32_t n, w, h, k;
  51. bds_state bds;
  52. u_char *stack;
  53. u_int32_t stackoffset;
  54. u_char *stacklevels;
  55. u_char *auth;
  56. u_char *keep;
  57. u_char *th_nodes;
  58. u_char *retain;
  59. treehash_inst *treehash;
  60. u_int32_t idx; /* state read from file */
  61. u_int32_t maxidx; /* restricted # of signatures */
  62. int have_state; /* .state file exists */
  63. int lockfd; /* locked in sshkey_xmss_get_state() */
  64. u_char allow_update; /* allow sshkey_xmss_update_state() */
  65. char *enc_ciphername;/* encrypt state with cipher */
  66. u_char *enc_keyiv; /* encrypt state with key */
  67. u_int32_t enc_keyiv_len; /* length of enc_keyiv */
  68. };
  69. int sshkey_xmss_init_bds_state(struct sshkey *);
  70. int sshkey_xmss_init_enc_key(struct sshkey *, const char *);
  71. void sshkey_xmss_free_bds(struct sshkey *);
  72. int sshkey_xmss_get_state_from_file(struct sshkey *, const char *,
  73. int *, sshkey_printfn *);
  74. int sshkey_xmss_encrypt_state(const struct sshkey *, struct sshbuf *,
  75. struct sshbuf **);
  76. int sshkey_xmss_decrypt_state(const struct sshkey *, struct sshbuf *,
  77. struct sshbuf **);
  78. int sshkey_xmss_serialize_enc_key(const struct sshkey *, struct sshbuf *);
  79. int sshkey_xmss_deserialize_enc_key(struct sshkey *, struct sshbuf *);
  80. #define PRINT(s...) do { if (pr) pr(s); } while (0)
  81. int
  82. sshkey_xmss_init(struct sshkey *key, const char *name)
  83. {
  84. struct ssh_xmss_state *state;
  85. if (key->xmss_state != NULL)
  86. return SSH_ERR_INVALID_FORMAT;
  87. if (name == NULL)
  88. return SSH_ERR_INVALID_FORMAT;
  89. state = calloc(sizeof(struct ssh_xmss_state), 1);
  90. if (state == NULL)
  91. return SSH_ERR_ALLOC_FAIL;
  92. if (strcmp(name, XMSS_SHA2_256_W16_H10_NAME) == 0) {
  93. state->n = 32;
  94. state->w = 16;
  95. state->h = 10;
  96. } else if (strcmp(name, XMSS_SHA2_256_W16_H16_NAME) == 0) {
  97. state->n = 32;
  98. state->w = 16;
  99. state->h = 16;
  100. } else if (strcmp(name, XMSS_SHA2_256_W16_H20_NAME) == 0) {
  101. state->n = 32;
  102. state->w = 16;
  103. state->h = 20;
  104. } else {
  105. free(state);
  106. return SSH_ERR_KEY_TYPE_UNKNOWN;
  107. }
  108. if ((key->xmss_name = strdup(name)) == NULL) {
  109. free(state);
  110. return SSH_ERR_ALLOC_FAIL;
  111. }
  112. state->k = 2; /* XXX hardcoded */
  113. state->lockfd = -1;
  114. if (xmss_set_params(&state->params, state->n, state->h, state->w,
  115. state->k) != 0) {
  116. free(state);
  117. return SSH_ERR_INVALID_FORMAT;
  118. }
  119. key->xmss_state = state;
  120. return 0;
  121. }
  122. void
  123. sshkey_xmss_free_state(struct sshkey *key)
  124. {
  125. struct ssh_xmss_state *state = key->xmss_state;
  126. sshkey_xmss_free_bds(key);
  127. if (state) {
  128. if (state->enc_keyiv) {
  129. explicit_bzero(state->enc_keyiv, state->enc_keyiv_len);
  130. free(state->enc_keyiv);
  131. }
  132. free(state->enc_ciphername);
  133. free(state);
  134. }
  135. key->xmss_state = NULL;
  136. }
  137. #define SSH_XMSS_K2_MAGIC "k=2"
  138. #define num_stack(x) ((x->h+1)*(x->n))
  139. #define num_stacklevels(x) (x->h+1)
  140. #define num_auth(x) ((x->h)*(x->n))
  141. #define num_keep(x) ((x->h >> 1)*(x->n))
  142. #define num_th_nodes(x) ((x->h - x->k)*(x->n))
  143. #define num_retain(x) (((1ULL << x->k) - x->k - 1) * (x->n))
  144. #define num_treehash(x) ((x->h) - (x->k))
  145. int
  146. sshkey_xmss_init_bds_state(struct sshkey *key)
  147. {
  148. struct ssh_xmss_state *state = key->xmss_state;
  149. u_int32_t i;
  150. state->stackoffset = 0;
  151. if ((state->stack = calloc(num_stack(state), 1)) == NULL ||
  152. (state->stacklevels = calloc(num_stacklevels(state), 1))== NULL ||
  153. (state->auth = calloc(num_auth(state), 1)) == NULL ||
  154. (state->keep = calloc(num_keep(state), 1)) == NULL ||
  155. (state->th_nodes = calloc(num_th_nodes(state), 1)) == NULL ||
  156. (state->retain = calloc(num_retain(state), 1)) == NULL ||
  157. (state->treehash = calloc(num_treehash(state),
  158. sizeof(treehash_inst))) == NULL) {
  159. sshkey_xmss_free_bds(key);
  160. return SSH_ERR_ALLOC_FAIL;
  161. }
  162. for (i = 0; i < state->h - state->k; i++)
  163. state->treehash[i].node = &state->th_nodes[state->n*i];
  164. xmss_set_bds_state(&state->bds, state->stack, state->stackoffset,
  165. state->stacklevels, state->auth, state->keep, state->treehash,
  166. state->retain, 0);
  167. return 0;
  168. }
  169. void
  170. sshkey_xmss_free_bds(struct sshkey *key)
  171. {
  172. struct ssh_xmss_state *state = key->xmss_state;
  173. if (state == NULL)
  174. return;
  175. free(state->stack);
  176. free(state->stacklevels);
  177. free(state->auth);
  178. free(state->keep);
  179. free(state->th_nodes);
  180. free(state->retain);
  181. free(state->treehash);
  182. state->stack = NULL;
  183. state->stacklevels = NULL;
  184. state->auth = NULL;
  185. state->keep = NULL;
  186. state->th_nodes = NULL;
  187. state->retain = NULL;
  188. state->treehash = NULL;
  189. }
  190. void *
  191. sshkey_xmss_params(const struct sshkey *key)
  192. {
  193. struct ssh_xmss_state *state = key->xmss_state;
  194. if (state == NULL)
  195. return NULL;
  196. return &state->params;
  197. }
  198. void *
  199. sshkey_xmss_bds_state(const struct sshkey *key)
  200. {
  201. struct ssh_xmss_state *state = key->xmss_state;
  202. if (state == NULL)
  203. return NULL;
  204. return &state->bds;
  205. }
  206. int
  207. sshkey_xmss_siglen(const struct sshkey *key, size_t *lenp)
  208. {
  209. struct ssh_xmss_state *state = key->xmss_state;
  210. if (lenp == NULL)
  211. return SSH_ERR_INVALID_ARGUMENT;
  212. if (state == NULL)
  213. return SSH_ERR_INVALID_FORMAT;
  214. *lenp = 4 + state->n +
  215. state->params.wots_par.keysize +
  216. state->h * state->n;
  217. return 0;
  218. }
  219. size_t
  220. sshkey_xmss_pklen(const struct sshkey *key)
  221. {
  222. struct ssh_xmss_state *state = key->xmss_state;
  223. if (state == NULL)
  224. return 0;
  225. return state->n * 2;
  226. }
  227. size_t
  228. sshkey_xmss_sklen(const struct sshkey *key)
  229. {
  230. struct ssh_xmss_state *state = key->xmss_state;
  231. if (state == NULL)
  232. return 0;
  233. return state->n * 4 + 4;
  234. }
  235. int
  236. sshkey_xmss_init_enc_key(struct sshkey *k, const char *ciphername)
  237. {
  238. struct ssh_xmss_state *state = k->xmss_state;
  239. const struct sshcipher *cipher;
  240. size_t keylen = 0, ivlen = 0;
  241. if (state == NULL)
  242. return SSH_ERR_INVALID_ARGUMENT;
  243. if ((cipher = cipher_by_name(ciphername)) == NULL)
  244. return SSH_ERR_INTERNAL_ERROR;
  245. if ((state->enc_ciphername = strdup(ciphername)) == NULL)
  246. return SSH_ERR_ALLOC_FAIL;
  247. keylen = cipher_keylen(cipher);
  248. ivlen = cipher_ivlen(cipher);
  249. state->enc_keyiv_len = keylen + ivlen;
  250. if ((state->enc_keyiv = calloc(state->enc_keyiv_len, 1)) == NULL) {
  251. free(state->enc_ciphername);
  252. state->enc_ciphername = NULL;
  253. return SSH_ERR_ALLOC_FAIL;
  254. }
  255. arc4random_buf(state->enc_keyiv, state->enc_keyiv_len);
  256. return 0;
  257. }
  258. int
  259. sshkey_xmss_serialize_enc_key(const struct sshkey *k, struct sshbuf *b)
  260. {
  261. struct ssh_xmss_state *state = k->xmss_state;
  262. int r;
  263. if (state == NULL || state->enc_keyiv == NULL ||
  264. state->enc_ciphername == NULL)
  265. return SSH_ERR_INVALID_ARGUMENT;
  266. if ((r = sshbuf_put_cstring(b, state->enc_ciphername)) != 0 ||
  267. (r = sshbuf_put_string(b, state->enc_keyiv,
  268. state->enc_keyiv_len)) != 0)
  269. return r;
  270. return 0;
  271. }
  272. int
  273. sshkey_xmss_deserialize_enc_key(struct sshkey *k, struct sshbuf *b)
  274. {
  275. struct ssh_xmss_state *state = k->xmss_state;
  276. size_t len;
  277. int r;
  278. if (state == NULL)
  279. return SSH_ERR_INVALID_ARGUMENT;
  280. if ((r = sshbuf_get_cstring(b, &state->enc_ciphername, NULL)) != 0 ||
  281. (r = sshbuf_get_string(b, &state->enc_keyiv, &len)) != 0)
  282. return r;
  283. state->enc_keyiv_len = len;
  284. return 0;
  285. }
  286. int
  287. sshkey_xmss_serialize_pk_info(const struct sshkey *k, struct sshbuf *b,
  288. enum sshkey_serialize_rep opts)
  289. {
  290. struct ssh_xmss_state *state = k->xmss_state;
  291. u_char have_info = 1;
  292. u_int32_t idx;
  293. int r;
  294. if (state == NULL)
  295. return SSH_ERR_INVALID_ARGUMENT;
  296. if (opts != SSHKEY_SERIALIZE_INFO)
  297. return 0;
  298. idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx;
  299. if ((r = sshbuf_put_u8(b, have_info)) != 0 ||
  300. (r = sshbuf_put_u32(b, idx)) != 0 ||
  301. (r = sshbuf_put_u32(b, state->maxidx)) != 0)
  302. return r;
  303. return 0;
  304. }
  305. int
  306. sshkey_xmss_deserialize_pk_info(struct sshkey *k, struct sshbuf *b)
  307. {
  308. struct ssh_xmss_state *state = k->xmss_state;
  309. u_char have_info;
  310. int r;
  311. if (state == NULL)
  312. return SSH_ERR_INVALID_ARGUMENT;
  313. /* optional */
  314. if (sshbuf_len(b) == 0)
  315. return 0;
  316. if ((r = sshbuf_get_u8(b, &have_info)) != 0)
  317. return r;
  318. if (have_info != 1)
  319. return SSH_ERR_INVALID_ARGUMENT;
  320. if ((r = sshbuf_get_u32(b, &state->idx)) != 0 ||
  321. (r = sshbuf_get_u32(b, &state->maxidx)) != 0)
  322. return r;
  323. return 0;
  324. }
  325. int
  326. sshkey_xmss_generate_private_key(struct sshkey *k, u_int bits)
  327. {
  328. int r;
  329. const char *name;
  330. if (bits == 10) {
  331. name = XMSS_SHA2_256_W16_H10_NAME;
  332. } else if (bits == 16) {
  333. name = XMSS_SHA2_256_W16_H16_NAME;
  334. } else if (bits == 20) {
  335. name = XMSS_SHA2_256_W16_H20_NAME;
  336. } else {
  337. name = XMSS_DEFAULT_NAME;
  338. }
  339. if ((r = sshkey_xmss_init(k, name)) != 0 ||
  340. (r = sshkey_xmss_init_bds_state(k)) != 0 ||
  341. (r = sshkey_xmss_init_enc_key(k, XMSS_CIPHERNAME)) != 0)
  342. return r;
  343. if ((k->xmss_pk = malloc(sshkey_xmss_pklen(k))) == NULL ||
  344. (k->xmss_sk = malloc(sshkey_xmss_sklen(k))) == NULL) {
  345. return SSH_ERR_ALLOC_FAIL;
  346. }
  347. xmss_keypair(k->xmss_pk, k->xmss_sk, sshkey_xmss_bds_state(k),
  348. sshkey_xmss_params(k));
  349. return 0;
  350. }
  351. int
  352. sshkey_xmss_get_state_from_file(struct sshkey *k, const char *filename,
  353. int *have_file, sshkey_printfn *pr)
  354. {
  355. struct sshbuf *b = NULL, *enc = NULL;
  356. int ret = SSH_ERR_SYSTEM_ERROR, r, fd = -1;
  357. u_int32_t len;
  358. unsigned char buf[4], *data = NULL;
  359. *have_file = 0;
  360. if ((fd = open(filename, O_RDONLY)) >= 0) {
  361. *have_file = 1;
  362. if (atomicio(read, fd, buf, sizeof(buf)) != sizeof(buf)) {
  363. PRINT("%s: corrupt state file: %s", __func__, filename);
  364. goto done;
  365. }
  366. len = PEEK_U32(buf);
  367. if ((data = calloc(len, 1)) == NULL) {
  368. ret = SSH_ERR_ALLOC_FAIL;
  369. goto done;
  370. }
  371. if (atomicio(read, fd, data, len) != len) {
  372. PRINT("%s: cannot read blob: %s", __func__, filename);
  373. goto done;
  374. }
  375. if ((enc = sshbuf_from(data, len)) == NULL) {
  376. ret = SSH_ERR_ALLOC_FAIL;
  377. goto done;
  378. }
  379. sshkey_xmss_free_bds(k);
  380. if ((r = sshkey_xmss_decrypt_state(k, enc, &b)) != 0) {
  381. ret = r;
  382. goto done;
  383. }
  384. if ((r = sshkey_xmss_deserialize_state(k, b)) != 0) {
  385. ret = r;
  386. goto done;
  387. }
  388. ret = 0;
  389. }
  390. done:
  391. if (fd != -1)
  392. close(fd);
  393. free(data);
  394. sshbuf_free(enc);
  395. sshbuf_free(b);
  396. return ret;
  397. }
  398. int
  399. sshkey_xmss_get_state(const struct sshkey *k, sshkey_printfn *pr)
  400. {
  401. struct ssh_xmss_state *state = k->xmss_state;
  402. u_int32_t idx = 0;
  403. char *filename = NULL;
  404. char *statefile = NULL, *ostatefile = NULL, *lockfile = NULL;
  405. int lockfd = -1, have_state = 0, have_ostate, tries = 0;
  406. int ret = SSH_ERR_INVALID_ARGUMENT, r;
  407. if (state == NULL)
  408. goto done;
  409. /*
  410. * If maxidx is set, then we are allowed a limited number
  411. * of signatures, but don't need to access the disk.
  412. * Otherwise we need to deal with the on-disk state.
  413. */
  414. if (state->maxidx) {
  415. /* xmss_sk always contains the current state */
  416. idx = PEEK_U32(k->xmss_sk);
  417. if (idx < state->maxidx) {
  418. state->allow_update = 1;
  419. return 0;
  420. }
  421. return SSH_ERR_INVALID_ARGUMENT;
  422. }
  423. if ((filename = k->xmss_filename) == NULL)
  424. goto done;
  425. if (asprintf(&lockfile, "%s.lock", filename) == -1 ||
  426. asprintf(&statefile, "%s.state", filename) == -1 ||
  427. asprintf(&ostatefile, "%s.ostate", filename) == -1) {
  428. ret = SSH_ERR_ALLOC_FAIL;
  429. goto done;
  430. }
  431. if ((lockfd = open(lockfile, O_CREAT|O_RDONLY, 0600)) == -1) {
  432. ret = SSH_ERR_SYSTEM_ERROR;
  433. PRINT("%s: cannot open/create: %s", __func__, lockfile);
  434. goto done;
  435. }
  436. while (flock(lockfd, LOCK_EX|LOCK_NB) == -1) {
  437. if (errno != EWOULDBLOCK) {
  438. ret = SSH_ERR_SYSTEM_ERROR;
  439. PRINT("%s: cannot lock: %s", __func__, lockfile);
  440. goto done;
  441. }
  442. if (++tries > 10) {
  443. ret = SSH_ERR_SYSTEM_ERROR;
  444. PRINT("%s: giving up on: %s", __func__, lockfile);
  445. goto done;
  446. }
  447. usleep(1000*100*tries);
  448. }
  449. /* XXX no longer const */
  450. if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k,
  451. statefile, &have_state, pr)) != 0) {
  452. if ((r = sshkey_xmss_get_state_from_file((struct sshkey *)k,
  453. ostatefile, &have_ostate, pr)) == 0) {
  454. state->allow_update = 1;
  455. r = sshkey_xmss_forward_state(k, 1);
  456. state->idx = PEEK_U32(k->xmss_sk);
  457. state->allow_update = 0;
  458. }
  459. }
  460. if (!have_state && !have_ostate) {
  461. /* check that bds state is initialized */
  462. if (state->bds.auth == NULL)
  463. goto done;
  464. PRINT("%s: start from scratch idx 0: %u", __func__, state->idx);
  465. } else if (r != 0) {
  466. ret = r;
  467. goto done;
  468. }
  469. if (state->idx + 1 < state->idx) {
  470. PRINT("%s: state wrap: %u", __func__, state->idx);
  471. goto done;
  472. }
  473. state->have_state = have_state;
  474. state->lockfd = lockfd;
  475. state->allow_update = 1;
  476. lockfd = -1;
  477. ret = 0;
  478. done:
  479. if (lockfd != -1)
  480. close(lockfd);
  481. free(lockfile);
  482. free(statefile);
  483. free(ostatefile);
  484. return ret;
  485. }
  486. int
  487. sshkey_xmss_forward_state(const struct sshkey *k, u_int32_t reserve)
  488. {
  489. struct ssh_xmss_state *state = k->xmss_state;
  490. u_char *sig = NULL;
  491. size_t required_siglen;
  492. unsigned long long smlen;
  493. u_char data;
  494. int ret, r;
  495. if (state == NULL || !state->allow_update)
  496. return SSH_ERR_INVALID_ARGUMENT;
  497. if (reserve == 0)
  498. return SSH_ERR_INVALID_ARGUMENT;
  499. if (state->idx + reserve <= state->idx)
  500. return SSH_ERR_INVALID_ARGUMENT;
  501. if ((r = sshkey_xmss_siglen(k, &required_siglen)) != 0)
  502. return r;
  503. if ((sig = malloc(required_siglen)) == NULL)
  504. return SSH_ERR_ALLOC_FAIL;
  505. while (reserve-- > 0) {
  506. state->idx = PEEK_U32(k->xmss_sk);
  507. smlen = required_siglen;
  508. if ((ret = xmss_sign(k->xmss_sk, sshkey_xmss_bds_state(k),
  509. sig, &smlen, &data, 0, sshkey_xmss_params(k))) != 0) {
  510. r = SSH_ERR_INVALID_ARGUMENT;
  511. break;
  512. }
  513. }
  514. free(sig);
  515. return r;
  516. }
  517. int
  518. sshkey_xmss_update_state(const struct sshkey *k, sshkey_printfn *pr)
  519. {
  520. struct ssh_xmss_state *state = k->xmss_state;
  521. struct sshbuf *b = NULL, *enc = NULL;
  522. u_int32_t idx = 0;
  523. unsigned char buf[4];
  524. char *filename = NULL;
  525. char *statefile = NULL, *ostatefile = NULL, *nstatefile = NULL;
  526. int fd = -1;
  527. int ret = SSH_ERR_INVALID_ARGUMENT;
  528. if (state == NULL || !state->allow_update)
  529. return ret;
  530. if (state->maxidx) {
  531. /* no update since the number of signatures is limited */
  532. ret = 0;
  533. goto done;
  534. }
  535. idx = PEEK_U32(k->xmss_sk);
  536. if (idx == state->idx) {
  537. /* no signature happened, no need to update */
  538. ret = 0;
  539. goto done;
  540. } else if (idx != state->idx + 1) {
  541. PRINT("%s: more than one signature happened: idx %u state %u",
  542. __func__, idx, state->idx);
  543. goto done;
  544. }
  545. state->idx = idx;
  546. if ((filename = k->xmss_filename) == NULL)
  547. goto done;
  548. if (asprintf(&statefile, "%s.state", filename) == -1 ||
  549. asprintf(&ostatefile, "%s.ostate", filename) == -1 ||
  550. asprintf(&nstatefile, "%s.nstate", filename) == -1) {
  551. ret = SSH_ERR_ALLOC_FAIL;
  552. goto done;
  553. }
  554. unlink(nstatefile);
  555. if ((b = sshbuf_new()) == NULL) {
  556. ret = SSH_ERR_ALLOC_FAIL;
  557. goto done;
  558. }
  559. if ((ret = sshkey_xmss_serialize_state(k, b)) != 0) {
  560. PRINT("%s: SERLIALIZE FAILED: %d", __func__, ret);
  561. goto done;
  562. }
  563. if ((ret = sshkey_xmss_encrypt_state(k, b, &enc)) != 0) {
  564. PRINT("%s: ENCRYPT FAILED: %d", __func__, ret);
  565. goto done;
  566. }
  567. if ((fd = open(nstatefile, O_CREAT|O_WRONLY|O_EXCL, 0600)) == -1) {
  568. ret = SSH_ERR_SYSTEM_ERROR;
  569. PRINT("%s: open new state file: %s", __func__, nstatefile);
  570. goto done;
  571. }
  572. POKE_U32(buf, sshbuf_len(enc));
  573. if (atomicio(vwrite, fd, buf, sizeof(buf)) != sizeof(buf)) {
  574. ret = SSH_ERR_SYSTEM_ERROR;
  575. PRINT("%s: write new state file hdr: %s", __func__, nstatefile);
  576. close(fd);
  577. goto done;
  578. }
  579. if (atomicio(vwrite, fd, sshbuf_mutable_ptr(enc), sshbuf_len(enc)) !=
  580. sshbuf_len(enc)) {
  581. ret = SSH_ERR_SYSTEM_ERROR;
  582. PRINT("%s: write new state file data: %s", __func__, nstatefile);
  583. close(fd);
  584. goto done;
  585. }
  586. if (fsync(fd) == -1) {
  587. ret = SSH_ERR_SYSTEM_ERROR;
  588. PRINT("%s: sync new state file: %s", __func__, nstatefile);
  589. close(fd);
  590. goto done;
  591. }
  592. if (close(fd) == -1) {
  593. ret = SSH_ERR_SYSTEM_ERROR;
  594. PRINT("%s: close new state file: %s", __func__, nstatefile);
  595. goto done;
  596. }
  597. if (state->have_state) {
  598. unlink(ostatefile);
  599. if (link(statefile, ostatefile)) {
  600. ret = SSH_ERR_SYSTEM_ERROR;
  601. PRINT("%s: backup state %s to %s", __func__, statefile,
  602. ostatefile);
  603. goto done;
  604. }
  605. }
  606. if (rename(nstatefile, statefile) == -1) {
  607. ret = SSH_ERR_SYSTEM_ERROR;
  608. PRINT("%s: rename %s to %s", __func__, nstatefile, statefile);
  609. goto done;
  610. }
  611. ret = 0;
  612. done:
  613. if (state->lockfd != -1) {
  614. close(state->lockfd);
  615. state->lockfd = -1;
  616. }
  617. if (nstatefile)
  618. unlink(nstatefile);
  619. free(statefile);
  620. free(ostatefile);
  621. free(nstatefile);
  622. sshbuf_free(b);
  623. sshbuf_free(enc);
  624. return ret;
  625. }
  626. int
  627. sshkey_xmss_serialize_state(const struct sshkey *k, struct sshbuf *b)
  628. {
  629. struct ssh_xmss_state *state = k->xmss_state;
  630. treehash_inst *th;
  631. u_int32_t i, node;
  632. int r;
  633. if (state == NULL)
  634. return SSH_ERR_INVALID_ARGUMENT;
  635. if (state->stack == NULL)
  636. return SSH_ERR_INVALID_ARGUMENT;
  637. state->stackoffset = state->bds.stackoffset; /* copy back */
  638. if ((r = sshbuf_put_cstring(b, SSH_XMSS_K2_MAGIC)) != 0 ||
  639. (r = sshbuf_put_u32(b, state->idx)) != 0 ||
  640. (r = sshbuf_put_string(b, state->stack, num_stack(state))) != 0 ||
  641. (r = sshbuf_put_u32(b, state->stackoffset)) != 0 ||
  642. (r = sshbuf_put_string(b, state->stacklevels, num_stacklevels(state))) != 0 ||
  643. (r = sshbuf_put_string(b, state->auth, num_auth(state))) != 0 ||
  644. (r = sshbuf_put_string(b, state->keep, num_keep(state))) != 0 ||
  645. (r = sshbuf_put_string(b, state->th_nodes, num_th_nodes(state))) != 0 ||
  646. (r = sshbuf_put_string(b, state->retain, num_retain(state))) != 0 ||
  647. (r = sshbuf_put_u32(b, num_treehash(state))) != 0)
  648. return r;
  649. for (i = 0; i < num_treehash(state); i++) {
  650. th = &state->treehash[i];
  651. node = th->node - state->th_nodes;
  652. if ((r = sshbuf_put_u32(b, th->h)) != 0 ||
  653. (r = sshbuf_put_u32(b, th->next_idx)) != 0 ||
  654. (r = sshbuf_put_u32(b, th->stackusage)) != 0 ||
  655. (r = sshbuf_put_u8(b, th->completed)) != 0 ||
  656. (r = sshbuf_put_u32(b, node)) != 0)
  657. return r;
  658. }
  659. return 0;
  660. }
  661. int
  662. sshkey_xmss_serialize_state_opt(const struct sshkey *k, struct sshbuf *b,
  663. enum sshkey_serialize_rep opts)
  664. {
  665. struct ssh_xmss_state *state = k->xmss_state;
  666. int r = SSH_ERR_INVALID_ARGUMENT;
  667. u_char have_stack, have_filename, have_enc;
  668. if (state == NULL)
  669. return SSH_ERR_INVALID_ARGUMENT;
  670. if ((r = sshbuf_put_u8(b, opts)) != 0)
  671. return r;
  672. switch (opts) {
  673. case SSHKEY_SERIALIZE_STATE:
  674. r = sshkey_xmss_serialize_state(k, b);
  675. break;
  676. case SSHKEY_SERIALIZE_FULL:
  677. if ((r = sshkey_xmss_serialize_enc_key(k, b)) != 0)
  678. return r;
  679. r = sshkey_xmss_serialize_state(k, b);
  680. break;
  681. case SSHKEY_SERIALIZE_SHIELD:
  682. /* all of stack/filename/enc are optional */
  683. have_stack = state->stack != NULL;
  684. if ((r = sshbuf_put_u8(b, have_stack)) != 0)
  685. return r;
  686. if (have_stack) {
  687. state->idx = PEEK_U32(k->xmss_sk); /* update */
  688. if ((r = sshkey_xmss_serialize_state(k, b)) != 0)
  689. return r;
  690. }
  691. have_filename = k->xmss_filename != NULL;
  692. if ((r = sshbuf_put_u8(b, have_filename)) != 0)
  693. return r;
  694. if (have_filename &&
  695. (r = sshbuf_put_cstring(b, k->xmss_filename)) != 0)
  696. return r;
  697. have_enc = state->enc_keyiv != NULL;
  698. if ((r = sshbuf_put_u8(b, have_enc)) != 0)
  699. return r;
  700. if (have_enc &&
  701. (r = sshkey_xmss_serialize_enc_key(k, b)) != 0)
  702. return r;
  703. if ((r = sshbuf_put_u32(b, state->maxidx)) != 0 ||
  704. (r = sshbuf_put_u8(b, state->allow_update)) != 0)
  705. return r;
  706. break;
  707. case SSHKEY_SERIALIZE_DEFAULT:
  708. r = 0;
  709. break;
  710. default:
  711. r = SSH_ERR_INVALID_ARGUMENT;
  712. break;
  713. }
  714. return r;
  715. }
  716. int
  717. sshkey_xmss_deserialize_state(struct sshkey *k, struct sshbuf *b)
  718. {
  719. struct ssh_xmss_state *state = k->xmss_state;
  720. treehash_inst *th;
  721. u_int32_t i, lh, node;
  722. size_t ls, lsl, la, lk, ln, lr;
  723. char *magic;
  724. int r = SSH_ERR_INTERNAL_ERROR;
  725. if (state == NULL)
  726. return SSH_ERR_INVALID_ARGUMENT;
  727. if (k->xmss_sk == NULL)
  728. return SSH_ERR_INVALID_ARGUMENT;
  729. if ((state->treehash = calloc(num_treehash(state),
  730. sizeof(treehash_inst))) == NULL)
  731. return SSH_ERR_ALLOC_FAIL;
  732. if ((r = sshbuf_get_cstring(b, &magic, NULL)) != 0 ||
  733. (r = sshbuf_get_u32(b, &state->idx)) != 0 ||
  734. (r = sshbuf_get_string(b, &state->stack, &ls)) != 0 ||
  735. (r = sshbuf_get_u32(b, &state->stackoffset)) != 0 ||
  736. (r = sshbuf_get_string(b, &state->stacklevels, &lsl)) != 0 ||
  737. (r = sshbuf_get_string(b, &state->auth, &la)) != 0 ||
  738. (r = sshbuf_get_string(b, &state->keep, &lk)) != 0 ||
  739. (r = sshbuf_get_string(b, &state->th_nodes, &ln)) != 0 ||
  740. (r = sshbuf_get_string(b, &state->retain, &lr)) != 0 ||
  741. (r = sshbuf_get_u32(b, &lh)) != 0)
  742. goto out;
  743. if (strcmp(magic, SSH_XMSS_K2_MAGIC) != 0) {
  744. r = SSH_ERR_INVALID_ARGUMENT;
  745. goto out;
  746. }
  747. /* XXX check stackoffset */
  748. if (ls != num_stack(state) ||
  749. lsl != num_stacklevels(state) ||
  750. la != num_auth(state) ||
  751. lk != num_keep(state) ||
  752. ln != num_th_nodes(state) ||
  753. lr != num_retain(state) ||
  754. lh != num_treehash(state)) {
  755. r = SSH_ERR_INVALID_ARGUMENT;
  756. goto out;
  757. }
  758. for (i = 0; i < num_treehash(state); i++) {
  759. th = &state->treehash[i];
  760. if ((r = sshbuf_get_u32(b, &th->h)) != 0 ||
  761. (r = sshbuf_get_u32(b, &th->next_idx)) != 0 ||
  762. (r = sshbuf_get_u32(b, &th->stackusage)) != 0 ||
  763. (r = sshbuf_get_u8(b, &th->completed)) != 0 ||
  764. (r = sshbuf_get_u32(b, &node)) != 0)
  765. goto out;
  766. if (node < num_th_nodes(state))
  767. th->node = &state->th_nodes[node];
  768. }
  769. POKE_U32(k->xmss_sk, state->idx);
  770. xmss_set_bds_state(&state->bds, state->stack, state->stackoffset,
  771. state->stacklevels, state->auth, state->keep, state->treehash,
  772. state->retain, 0);
  773. /* success */
  774. r = 0;
  775. out:
  776. free(magic);
  777. return r;
  778. }
  779. int
  780. sshkey_xmss_deserialize_state_opt(struct sshkey *k, struct sshbuf *b)
  781. {
  782. struct ssh_xmss_state *state = k->xmss_state;
  783. enum sshkey_serialize_rep opts;
  784. u_char have_state, have_stack, have_filename, have_enc;
  785. int r;
  786. if ((r = sshbuf_get_u8(b, &have_state)) != 0)
  787. return r;
  788. opts = have_state;
  789. switch (opts) {
  790. case SSHKEY_SERIALIZE_DEFAULT:
  791. r = 0;
  792. break;
  793. case SSHKEY_SERIALIZE_SHIELD:
  794. if ((r = sshbuf_get_u8(b, &have_stack)) != 0)
  795. return r;
  796. if (have_stack &&
  797. (r = sshkey_xmss_deserialize_state(k, b)) != 0)
  798. return r;
  799. if ((r = sshbuf_get_u8(b, &have_filename)) != 0)
  800. return r;
  801. if (have_filename &&
  802. (r = sshbuf_get_cstring(b, &k->xmss_filename, NULL)) != 0)
  803. return r;
  804. if ((r = sshbuf_get_u8(b, &have_enc)) != 0)
  805. return r;
  806. if (have_enc &&
  807. (r = sshkey_xmss_deserialize_enc_key(k, b)) != 0)
  808. return r;
  809. if ((r = sshbuf_get_u32(b, &state->maxidx)) != 0 ||
  810. (r = sshbuf_get_u8(b, &state->allow_update)) != 0)
  811. return r;
  812. break;
  813. case SSHKEY_SERIALIZE_STATE:
  814. if ((r = sshkey_xmss_deserialize_state(k, b)) != 0)
  815. return r;
  816. break;
  817. case SSHKEY_SERIALIZE_FULL:
  818. if ((r = sshkey_xmss_deserialize_enc_key(k, b)) != 0 ||
  819. (r = sshkey_xmss_deserialize_state(k, b)) != 0)
  820. return r;
  821. break;
  822. default:
  823. r = SSH_ERR_INVALID_FORMAT;
  824. break;
  825. }
  826. return r;
  827. }
  828. int
  829. sshkey_xmss_encrypt_state(const struct sshkey *k, struct sshbuf *b,
  830. struct sshbuf **retp)
  831. {
  832. struct ssh_xmss_state *state = k->xmss_state;
  833. struct sshbuf *encrypted = NULL, *encoded = NULL, *padded = NULL;
  834. struct sshcipher_ctx *ciphercontext = NULL;
  835. const struct sshcipher *cipher;
  836. u_char *cp, *key, *iv = NULL;
  837. size_t i, keylen, ivlen, blocksize, authlen, encrypted_len, aadlen;
  838. int r = SSH_ERR_INTERNAL_ERROR;
  839. if (retp != NULL)
  840. *retp = NULL;
  841. if (state == NULL ||
  842. state->enc_keyiv == NULL ||
  843. state->enc_ciphername == NULL)
  844. return SSH_ERR_INTERNAL_ERROR;
  845. if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) {
  846. r = SSH_ERR_INTERNAL_ERROR;
  847. goto out;
  848. }
  849. blocksize = cipher_blocksize(cipher);
  850. keylen = cipher_keylen(cipher);
  851. ivlen = cipher_ivlen(cipher);
  852. authlen = cipher_authlen(cipher);
  853. if (state->enc_keyiv_len != keylen + ivlen) {
  854. r = SSH_ERR_INVALID_FORMAT;
  855. goto out;
  856. }
  857. key = state->enc_keyiv;
  858. if ((encrypted = sshbuf_new()) == NULL ||
  859. (encoded = sshbuf_new()) == NULL ||
  860. (padded = sshbuf_new()) == NULL ||
  861. (iv = malloc(ivlen)) == NULL) {
  862. r = SSH_ERR_ALLOC_FAIL;
  863. goto out;
  864. }
  865. /* replace first 4 bytes of IV with index to ensure uniqueness */
  866. memcpy(iv, key + keylen, ivlen);
  867. POKE_U32(iv, state->idx);
  868. if ((r = sshbuf_put(encoded, XMSS_MAGIC, sizeof(XMSS_MAGIC))) != 0 ||
  869. (r = sshbuf_put_u32(encoded, state->idx)) != 0)
  870. goto out;
  871. /* padded state will be encrypted */
  872. if ((r = sshbuf_putb(padded, b)) != 0)
  873. goto out;
  874. i = 0;
  875. while (sshbuf_len(padded) % blocksize) {
  876. if ((r = sshbuf_put_u8(padded, ++i & 0xff)) != 0)
  877. goto out;
  878. }
  879. encrypted_len = sshbuf_len(padded);
  880. /* header including the length of state is used as AAD */
  881. if ((r = sshbuf_put_u32(encoded, encrypted_len)) != 0)
  882. goto out;
  883. aadlen = sshbuf_len(encoded);
  884. /* concat header and state */
  885. if ((r = sshbuf_putb(encoded, padded)) != 0)
  886. goto out;
  887. /* reserve space for encryption of encoded data plus auth tag */
  888. /* encrypt at offset addlen */
  889. if ((r = sshbuf_reserve(encrypted,
  890. encrypted_len + aadlen + authlen, &cp)) != 0 ||
  891. (r = cipher_init(&ciphercontext, cipher, key, keylen,
  892. iv, ivlen, 1)) != 0 ||
  893. (r = cipher_crypt(ciphercontext, 0, cp, sshbuf_ptr(encoded),
  894. encrypted_len, aadlen, authlen)) != 0)
  895. goto out;
  896. /* success */
  897. r = 0;
  898. out:
  899. if (retp != NULL) {
  900. *retp = encrypted;
  901. encrypted = NULL;
  902. }
  903. sshbuf_free(padded);
  904. sshbuf_free(encoded);
  905. sshbuf_free(encrypted);
  906. cipher_free(ciphercontext);
  907. free(iv);
  908. return r;
  909. }
  910. int
  911. sshkey_xmss_decrypt_state(const struct sshkey *k, struct sshbuf *encoded,
  912. struct sshbuf **retp)
  913. {
  914. struct ssh_xmss_state *state = k->xmss_state;
  915. struct sshbuf *copy = NULL, *decrypted = NULL;
  916. struct sshcipher_ctx *ciphercontext = NULL;
  917. const struct sshcipher *cipher = NULL;
  918. u_char *key, *iv = NULL, *dp;
  919. size_t keylen, ivlen, authlen, aadlen;
  920. u_int blocksize, encrypted_len, index;
  921. int r = SSH_ERR_INTERNAL_ERROR;
  922. if (retp != NULL)
  923. *retp = NULL;
  924. if (state == NULL ||
  925. state->enc_keyiv == NULL ||
  926. state->enc_ciphername == NULL)
  927. return SSH_ERR_INTERNAL_ERROR;
  928. if ((cipher = cipher_by_name(state->enc_ciphername)) == NULL) {
  929. r = SSH_ERR_INVALID_FORMAT;
  930. goto out;
  931. }
  932. blocksize = cipher_blocksize(cipher);
  933. keylen = cipher_keylen(cipher);
  934. ivlen = cipher_ivlen(cipher);
  935. authlen = cipher_authlen(cipher);
  936. if (state->enc_keyiv_len != keylen + ivlen) {
  937. r = SSH_ERR_INTERNAL_ERROR;
  938. goto out;
  939. }
  940. key = state->enc_keyiv;
  941. if ((copy = sshbuf_fromb(encoded)) == NULL ||
  942. (decrypted = sshbuf_new()) == NULL ||
  943. (iv = malloc(ivlen)) == NULL) {
  944. r = SSH_ERR_ALLOC_FAIL;
  945. goto out;
  946. }
  947. /* check magic */
  948. if (sshbuf_len(encoded) < sizeof(XMSS_MAGIC) ||
  949. memcmp(sshbuf_ptr(encoded), XMSS_MAGIC, sizeof(XMSS_MAGIC))) {
  950. r = SSH_ERR_INVALID_FORMAT;
  951. goto out;
  952. }
  953. /* parse public portion */
  954. if ((r = sshbuf_consume(encoded, sizeof(XMSS_MAGIC))) != 0 ||
  955. (r = sshbuf_get_u32(encoded, &index)) != 0 ||
  956. (r = sshbuf_get_u32(encoded, &encrypted_len)) != 0)
  957. goto out;
  958. /* check size of encrypted key blob */
  959. if (encrypted_len < blocksize || (encrypted_len % blocksize) != 0) {
  960. r = SSH_ERR_INVALID_FORMAT;
  961. goto out;
  962. }
  963. /* check that an appropriate amount of auth data is present */
  964. if (sshbuf_len(encoded) < authlen ||
  965. sshbuf_len(encoded) - authlen < encrypted_len) {
  966. r = SSH_ERR_INVALID_FORMAT;
  967. goto out;
  968. }
  969. aadlen = sshbuf_len(copy) - sshbuf_len(encoded);
  970. /* replace first 4 bytes of IV with index to ensure uniqueness */
  971. memcpy(iv, key + keylen, ivlen);
  972. POKE_U32(iv, index);
  973. /* decrypt private state of key */
  974. if ((r = sshbuf_reserve(decrypted, aadlen + encrypted_len, &dp)) != 0 ||
  975. (r = cipher_init(&ciphercontext, cipher, key, keylen,
  976. iv, ivlen, 0)) != 0 ||
  977. (r = cipher_crypt(ciphercontext, 0, dp, sshbuf_ptr(copy),
  978. encrypted_len, aadlen, authlen)) != 0)
  979. goto out;
  980. /* there should be no trailing data */
  981. if ((r = sshbuf_consume(encoded, encrypted_len + authlen)) != 0)
  982. goto out;
  983. if (sshbuf_len(encoded) != 0) {
  984. r = SSH_ERR_INVALID_FORMAT;
  985. goto out;
  986. }
  987. /* remove AAD */
  988. if ((r = sshbuf_consume(decrypted, aadlen)) != 0)
  989. goto out;
  990. /* XXX encrypted includes unchecked padding */
  991. /* success */
  992. r = 0;
  993. if (retp != NULL) {
  994. *retp = decrypted;
  995. decrypted = NULL;
  996. }
  997. out:
  998. cipher_free(ciphercontext);
  999. sshbuf_free(copy);
  1000. sshbuf_free(decrypted);
  1001. free(iv);
  1002. return r;
  1003. }
  1004. u_int32_t
  1005. sshkey_xmss_signatures_left(const struct sshkey *k)
  1006. {
  1007. struct ssh_xmss_state *state = k->xmss_state;
  1008. u_int32_t idx;
  1009. if (sshkey_type_plain(k->type) == KEY_XMSS && state &&
  1010. state->maxidx) {
  1011. idx = k->xmss_sk ? PEEK_U32(k->xmss_sk) : state->idx;
  1012. if (idx < state->maxidx)
  1013. return state->maxidx - idx;
  1014. }
  1015. return 0;
  1016. }
  1017. int
  1018. sshkey_xmss_enable_maxsign(struct sshkey *k, u_int32_t maxsign)
  1019. {
  1020. struct ssh_xmss_state *state = k->xmss_state;
  1021. if (sshkey_type_plain(k->type) != KEY_XMSS)
  1022. return SSH_ERR_INVALID_ARGUMENT;
  1023. if (maxsign == 0)
  1024. return 0;
  1025. if (state->idx + maxsign < state->idx)
  1026. return SSH_ERR_INVALID_ARGUMENT;
  1027. state->maxidx = state->idx + maxsign;
  1028. return 0;
  1029. }
  1030. #endif /* WITH_XMSS */