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