xref: /freebsd-src/crypto/openssh/ssh-xmss.c (revision 535af610a4fdace6d50960c0ad9be0597eea7a1b)
1f374ba41SEd Maste /* $OpenBSD: ssh-xmss.c,v 1.14 2022/10/28 00:44:44 djm Exp $*/
247dd1d1bSDag-Erling Smørgrav /*
347dd1d1bSDag-Erling Smørgrav  * Copyright (c) 2017 Stefan-Lukas Gazdag.
447dd1d1bSDag-Erling Smørgrav  * Copyright (c) 2017 Markus Friedl.
547dd1d1bSDag-Erling Smørgrav  *
647dd1d1bSDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
747dd1d1bSDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
847dd1d1bSDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
947dd1d1bSDag-Erling Smørgrav  *
1047dd1d1bSDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1147dd1d1bSDag-Erling Smørgrav  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1247dd1d1bSDag-Erling Smørgrav  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1347dd1d1bSDag-Erling Smørgrav  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1447dd1d1bSDag-Erling Smørgrav  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1547dd1d1bSDag-Erling Smørgrav  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1647dd1d1bSDag-Erling Smørgrav  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1747dd1d1bSDag-Erling Smørgrav  */
1847dd1d1bSDag-Erling Smørgrav #include "includes.h"
1947dd1d1bSDag-Erling Smørgrav #ifdef WITH_XMSS
2047dd1d1bSDag-Erling Smørgrav 
2147dd1d1bSDag-Erling Smørgrav #define SSHKEY_INTERNAL
2247dd1d1bSDag-Erling Smørgrav #include <sys/types.h>
2347dd1d1bSDag-Erling Smørgrav #include <limits.h>
2447dd1d1bSDag-Erling Smørgrav 
2538a52bd3SEd Maste #include <stdlib.h>
2647dd1d1bSDag-Erling Smørgrav #include <string.h>
2747dd1d1bSDag-Erling Smørgrav #include <stdarg.h>
28*535af610SEd Maste #ifdef HAVE_STDINT_H
2938a52bd3SEd Maste # include <stdint.h>
30*535af610SEd Maste #endif
3147dd1d1bSDag-Erling Smørgrav #include <unistd.h>
3247dd1d1bSDag-Erling Smørgrav 
3347dd1d1bSDag-Erling Smørgrav #include "log.h"
3447dd1d1bSDag-Erling Smørgrav #include "sshbuf.h"
3547dd1d1bSDag-Erling Smørgrav #include "sshkey.h"
3647dd1d1bSDag-Erling Smørgrav #include "sshkey-xmss.h"
3747dd1d1bSDag-Erling Smørgrav #include "ssherr.h"
3847dd1d1bSDag-Erling Smørgrav #include "ssh.h"
3947dd1d1bSDag-Erling Smørgrav 
4047dd1d1bSDag-Erling Smørgrav #include "xmss_fast.h"
4147dd1d1bSDag-Erling Smørgrav 
42f374ba41SEd Maste static void
ssh_xmss_cleanup(struct sshkey * k)43f374ba41SEd Maste ssh_xmss_cleanup(struct sshkey *k)
44f374ba41SEd Maste {
45f374ba41SEd Maste 	freezero(k->xmss_pk, sshkey_xmss_pklen(k));
46f374ba41SEd Maste 	freezero(k->xmss_sk, sshkey_xmss_sklen(k));
47f374ba41SEd Maste 	sshkey_xmss_free_state(k);
48f374ba41SEd Maste 	free(k->xmss_name);
49f374ba41SEd Maste 	free(k->xmss_filename);
50f374ba41SEd Maste 	k->xmss_pk = NULL;
51f374ba41SEd Maste 	k->xmss_sk = NULL;
52f374ba41SEd Maste 	k->xmss_name = NULL;
53f374ba41SEd Maste 	k->xmss_filename = NULL;
54f374ba41SEd Maste }
55f374ba41SEd Maste 
56f374ba41SEd Maste static int
ssh_xmss_equal(const struct sshkey * a,const struct sshkey * b)57f374ba41SEd Maste ssh_xmss_equal(const struct sshkey *a, const struct sshkey *b)
58f374ba41SEd Maste {
59f374ba41SEd Maste 	if (a->xmss_pk == NULL || b->xmss_pk == NULL)
60f374ba41SEd Maste 		return 0;
61f374ba41SEd Maste 	if (sshkey_xmss_pklen(a) != sshkey_xmss_pklen(b))
62f374ba41SEd Maste 		return 0;
63f374ba41SEd Maste 	if (memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) != 0)
64f374ba41SEd Maste 		return 0;
65f374ba41SEd Maste 	return 1;
66f374ba41SEd Maste }
67f374ba41SEd Maste 
68f374ba41SEd Maste static int
ssh_xmss_serialize_public(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)69f374ba41SEd Maste ssh_xmss_serialize_public(const struct sshkey *key, struct sshbuf *b,
70f374ba41SEd Maste     enum sshkey_serialize_rep opts)
71f374ba41SEd Maste {
72f374ba41SEd Maste 	int r;
73f374ba41SEd Maste 
74f374ba41SEd Maste 	if (key->xmss_name == NULL || key->xmss_pk == NULL ||
75f374ba41SEd Maste 	    sshkey_xmss_pklen(key) == 0)
76f374ba41SEd Maste 		return SSH_ERR_INVALID_ARGUMENT;
77f374ba41SEd Maste 	if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
78f374ba41SEd Maste 	    (r = sshbuf_put_string(b, key->xmss_pk,
79f374ba41SEd Maste 	    sshkey_xmss_pklen(key))) != 0 ||
80f374ba41SEd Maste 	    (r = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
81f374ba41SEd Maste 		return r;
82f374ba41SEd Maste 
83f374ba41SEd Maste 	return 0;
84f374ba41SEd Maste }
85f374ba41SEd Maste 
86f374ba41SEd Maste static int
ssh_xmss_serialize_private(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)87f374ba41SEd Maste ssh_xmss_serialize_private(const struct sshkey *key, struct sshbuf *b,
88f374ba41SEd Maste     enum sshkey_serialize_rep opts)
89f374ba41SEd Maste {
90f374ba41SEd Maste 	int r;
91f374ba41SEd Maste 
92f374ba41SEd Maste 	if (key->xmss_name == NULL)
93f374ba41SEd Maste 		return SSH_ERR_INVALID_ARGUMENT;
94f374ba41SEd Maste 	/* Note: can't reuse ssh_xmss_serialize_public because of sk order */
95f374ba41SEd Maste 	if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
96f374ba41SEd Maste 	    (r = sshbuf_put_string(b, key->xmss_pk,
97f374ba41SEd Maste 	    sshkey_xmss_pklen(key))) != 0 ||
98f374ba41SEd Maste 	    (r = sshbuf_put_string(b, key->xmss_sk,
99f374ba41SEd Maste 	    sshkey_xmss_sklen(key))) != 0 ||
100f374ba41SEd Maste 	    (r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
101f374ba41SEd Maste 		return r;
102f374ba41SEd Maste 
103f374ba41SEd Maste 	return 0;
104f374ba41SEd Maste }
105f374ba41SEd Maste 
106f374ba41SEd Maste static int
ssh_xmss_copy_public(const struct sshkey * from,struct sshkey * to)107f374ba41SEd Maste ssh_xmss_copy_public(const struct sshkey *from, struct sshkey *to)
108f374ba41SEd Maste {
109f374ba41SEd Maste 	int r = SSH_ERR_INTERNAL_ERROR;
110f374ba41SEd Maste 	u_int32_t left;
111f374ba41SEd Maste 	size_t pklen;
112f374ba41SEd Maste 
113f374ba41SEd Maste 	if ((r = sshkey_xmss_init(to, from->xmss_name)) != 0)
114f374ba41SEd Maste 		return r;
115f374ba41SEd Maste 	if (from->xmss_pk == NULL)
116f374ba41SEd Maste 		return 0; /* XXX SSH_ERR_INTERNAL_ERROR ? */
117f374ba41SEd Maste 
118f374ba41SEd Maste 	if ((pklen = sshkey_xmss_pklen(from)) == 0 ||
119f374ba41SEd Maste 	    sshkey_xmss_pklen(to) != pklen)
120f374ba41SEd Maste 		return SSH_ERR_INTERNAL_ERROR;
121f374ba41SEd Maste 	if ((to->xmss_pk = malloc(pklen)) == NULL)
122f374ba41SEd Maste 		return SSH_ERR_ALLOC_FAIL;
123f374ba41SEd Maste 	memcpy(to->xmss_pk, from->xmss_pk, pklen);
124f374ba41SEd Maste 	/* simulate number of signatures left on pubkey */
125f374ba41SEd Maste 	left = sshkey_xmss_signatures_left(from);
126f374ba41SEd Maste 	if (left)
127f374ba41SEd Maste 		sshkey_xmss_enable_maxsign(to, left);
128f374ba41SEd Maste 	return 0;
129f374ba41SEd Maste }
130f374ba41SEd Maste 
131f374ba41SEd Maste static int
ssh_xmss_deserialize_public(const char * ktype,struct sshbuf * b,struct sshkey * key)132f374ba41SEd Maste ssh_xmss_deserialize_public(const char *ktype, struct sshbuf *b,
133f374ba41SEd Maste     struct sshkey *key)
134f374ba41SEd Maste {
135f374ba41SEd Maste 	size_t len = 0;
136f374ba41SEd Maste 	char *xmss_name = NULL;
137f374ba41SEd Maste 	u_char *pk = NULL;
138f374ba41SEd Maste 	int ret = SSH_ERR_INTERNAL_ERROR;
139f374ba41SEd Maste 
140f374ba41SEd Maste 	if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0)
141f374ba41SEd Maste 		goto out;
142f374ba41SEd Maste 	if ((ret = sshkey_xmss_init(key, xmss_name)) != 0)
143f374ba41SEd Maste 		goto out;
144f374ba41SEd Maste 	if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
145f374ba41SEd Maste 		goto out;
146f374ba41SEd Maste 	if (len == 0 || len != sshkey_xmss_pklen(key)) {
147f374ba41SEd Maste 		ret = SSH_ERR_INVALID_FORMAT;
148f374ba41SEd Maste 		goto out;
149f374ba41SEd Maste 	}
150f374ba41SEd Maste 	key->xmss_pk = pk;
151f374ba41SEd Maste 	pk = NULL;
152f374ba41SEd Maste 	if (!sshkey_is_cert(key) &&
153f374ba41SEd Maste 	    (ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0)
154f374ba41SEd Maste 		goto out;
155f374ba41SEd Maste 	/* success */
156f374ba41SEd Maste 	ret = 0;
157f374ba41SEd Maste  out:
158f374ba41SEd Maste 	free(xmss_name);
159f374ba41SEd Maste 	freezero(pk, len);
160f374ba41SEd Maste 	return ret;
161f374ba41SEd Maste }
162f374ba41SEd Maste 
163f374ba41SEd Maste static int
ssh_xmss_deserialize_private(const char * ktype,struct sshbuf * b,struct sshkey * key)164f374ba41SEd Maste ssh_xmss_deserialize_private(const char *ktype, struct sshbuf *b,
165f374ba41SEd Maste     struct sshkey *key)
166f374ba41SEd Maste {
167f374ba41SEd Maste 	int r;
168f374ba41SEd Maste 	char *xmss_name = NULL;
169f374ba41SEd Maste 	size_t pklen = 0, sklen = 0;
170f374ba41SEd Maste 	u_char *xmss_pk = NULL, *xmss_sk = NULL;
171f374ba41SEd Maste 
172f374ba41SEd Maste 	/* Note: can't reuse ssh_xmss_deserialize_public because of sk order */
173f374ba41SEd Maste 	if ((r = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0 ||
174f374ba41SEd Maste 	    (r = sshbuf_get_string(b, &xmss_pk, &pklen)) != 0 ||
175f374ba41SEd Maste 	    (r = sshbuf_get_string(b, &xmss_sk, &sklen)) != 0)
176f374ba41SEd Maste 		goto out;
177f374ba41SEd Maste 	if (!sshkey_is_cert(key) &&
178f374ba41SEd Maste 	    (r = sshkey_xmss_init(key, xmss_name)) != 0)
179f374ba41SEd Maste 		goto out;
180f374ba41SEd Maste 	if (pklen != sshkey_xmss_pklen(key) ||
181f374ba41SEd Maste 	    sklen != sshkey_xmss_sklen(key)) {
182f374ba41SEd Maste 		r = SSH_ERR_INVALID_FORMAT;
183f374ba41SEd Maste 		goto out;
184f374ba41SEd Maste 	}
185f374ba41SEd Maste 	key->xmss_pk = xmss_pk;
186f374ba41SEd Maste 	key->xmss_sk = xmss_sk;
187f374ba41SEd Maste 	xmss_pk = xmss_sk = NULL;
188f374ba41SEd Maste 	/* optional internal state */
189f374ba41SEd Maste 	if ((r = sshkey_xmss_deserialize_state_opt(key, b)) != 0)
190f374ba41SEd Maste 		goto out;
191f374ba41SEd Maste 	/* success */
192f374ba41SEd Maste 	r = 0;
193f374ba41SEd Maste  out:
194f374ba41SEd Maste 	free(xmss_name);
195f374ba41SEd Maste 	freezero(xmss_pk, pklen);
196f374ba41SEd Maste 	freezero(xmss_sk, sklen);
197f374ba41SEd Maste 	return r;
198f374ba41SEd Maste }
199f374ba41SEd Maste 
200f374ba41SEd Maste static int
ssh_xmss_sign(struct sshkey * key,u_char ** sigp,size_t * lenp,const u_char * data,size_t datalen,const char * alg,const char * sk_provider,const char * sk_pin,u_int compat)201f374ba41SEd Maste ssh_xmss_sign(struct sshkey *key,
202f374ba41SEd Maste     u_char **sigp, size_t *lenp,
203f374ba41SEd Maste     const u_char *data, size_t datalen,
204f374ba41SEd Maste     const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
20547dd1d1bSDag-Erling Smørgrav {
20647dd1d1bSDag-Erling Smørgrav 	u_char *sig = NULL;
20747dd1d1bSDag-Erling Smørgrav 	size_t slen = 0, len = 0, required_siglen;
20847dd1d1bSDag-Erling Smørgrav 	unsigned long long smlen;
20947dd1d1bSDag-Erling Smørgrav 	int r, ret;
21047dd1d1bSDag-Erling Smørgrav 	struct sshbuf *b = NULL;
21147dd1d1bSDag-Erling Smørgrav 
21247dd1d1bSDag-Erling Smørgrav 	if (lenp != NULL)
21347dd1d1bSDag-Erling Smørgrav 		*lenp = 0;
21447dd1d1bSDag-Erling Smørgrav 	if (sigp != NULL)
21547dd1d1bSDag-Erling Smørgrav 		*sigp = NULL;
21647dd1d1bSDag-Erling Smørgrav 
21747dd1d1bSDag-Erling Smørgrav 	if (key == NULL ||
21847dd1d1bSDag-Erling Smørgrav 	    sshkey_type_plain(key->type) != KEY_XMSS ||
21947dd1d1bSDag-Erling Smørgrav 	    key->xmss_sk == NULL ||
22047dd1d1bSDag-Erling Smørgrav 	    sshkey_xmss_params(key) == NULL)
22147dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
22247dd1d1bSDag-Erling Smørgrav 	if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
22347dd1d1bSDag-Erling Smørgrav 		return r;
22447dd1d1bSDag-Erling Smørgrav 	if (datalen >= INT_MAX - required_siglen)
22547dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
22647dd1d1bSDag-Erling Smørgrav 	smlen = slen = datalen + required_siglen;
22747dd1d1bSDag-Erling Smørgrav 	if ((sig = malloc(slen)) == NULL)
22847dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
22919261079SEd Maste 	if ((r = sshkey_xmss_get_state(key, 1)) != 0)
23047dd1d1bSDag-Erling Smørgrav 		goto out;
23147dd1d1bSDag-Erling Smørgrav 	if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen,
23247dd1d1bSDag-Erling Smørgrav 	    data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) {
23347dd1d1bSDag-Erling Smørgrav 		r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
23447dd1d1bSDag-Erling Smørgrav 		goto out;
23547dd1d1bSDag-Erling Smørgrav 	}
23647dd1d1bSDag-Erling Smørgrav 	/* encode signature */
23747dd1d1bSDag-Erling Smørgrav 	if ((b = sshbuf_new()) == NULL) {
23847dd1d1bSDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
23947dd1d1bSDag-Erling Smørgrav 		goto out;
24047dd1d1bSDag-Erling Smørgrav 	}
24147dd1d1bSDag-Erling Smørgrav 	if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 ||
24247dd1d1bSDag-Erling Smørgrav 	    (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
24347dd1d1bSDag-Erling Smørgrav 		goto out;
24447dd1d1bSDag-Erling Smørgrav 	len = sshbuf_len(b);
24547dd1d1bSDag-Erling Smørgrav 	if (sigp != NULL) {
24647dd1d1bSDag-Erling Smørgrav 		if ((*sigp = malloc(len)) == NULL) {
24747dd1d1bSDag-Erling Smørgrav 			r = SSH_ERR_ALLOC_FAIL;
24847dd1d1bSDag-Erling Smørgrav 			goto out;
24947dd1d1bSDag-Erling Smørgrav 		}
25047dd1d1bSDag-Erling Smørgrav 		memcpy(*sigp, sshbuf_ptr(b), len);
25147dd1d1bSDag-Erling Smørgrav 	}
25247dd1d1bSDag-Erling Smørgrav 	if (lenp != NULL)
25347dd1d1bSDag-Erling Smørgrav 		*lenp = len;
25447dd1d1bSDag-Erling Smørgrav 	/* success */
25547dd1d1bSDag-Erling Smørgrav 	r = 0;
25647dd1d1bSDag-Erling Smørgrav  out:
25719261079SEd Maste 	if ((ret = sshkey_xmss_update_state(key, 1)) != 0) {
25847dd1d1bSDag-Erling Smørgrav 		/* discard signature since we cannot update the state */
25947dd1d1bSDag-Erling Smørgrav 		if (r == 0 && sigp != NULL && *sigp != NULL) {
26047dd1d1bSDag-Erling Smørgrav 			explicit_bzero(*sigp, len);
26147dd1d1bSDag-Erling Smørgrav 			free(*sigp);
26247dd1d1bSDag-Erling Smørgrav 		}
26347dd1d1bSDag-Erling Smørgrav 		if (sigp != NULL)
26447dd1d1bSDag-Erling Smørgrav 			*sigp = NULL;
26547dd1d1bSDag-Erling Smørgrav 		if (lenp != NULL)
26647dd1d1bSDag-Erling Smørgrav 			*lenp = 0;
26747dd1d1bSDag-Erling Smørgrav 		r = ret;
26847dd1d1bSDag-Erling Smørgrav 	}
26947dd1d1bSDag-Erling Smørgrav 	sshbuf_free(b);
27019261079SEd Maste 	if (sig != NULL)
27119261079SEd Maste 		freezero(sig, slen);
27247dd1d1bSDag-Erling Smørgrav 
27347dd1d1bSDag-Erling Smørgrav 	return r;
27447dd1d1bSDag-Erling Smørgrav }
27547dd1d1bSDag-Erling Smørgrav 
276f374ba41SEd Maste static int
ssh_xmss_verify(const struct sshkey * key,const u_char * sig,size_t siglen,const u_char * data,size_t dlen,const char * alg,u_int compat,struct sshkey_sig_details ** detailsp)27747dd1d1bSDag-Erling Smørgrav ssh_xmss_verify(const struct sshkey *key,
278f374ba41SEd Maste     const u_char *sig, size_t siglen,
279f374ba41SEd Maste     const u_char *data, size_t dlen, const char *alg, u_int compat,
280f374ba41SEd Maste     struct sshkey_sig_details **detailsp)
28147dd1d1bSDag-Erling Smørgrav {
28247dd1d1bSDag-Erling Smørgrav 	struct sshbuf *b = NULL;
28347dd1d1bSDag-Erling Smørgrav 	char *ktype = NULL;
28447dd1d1bSDag-Erling Smørgrav 	const u_char *sigblob;
28547dd1d1bSDag-Erling Smørgrav 	u_char *sm = NULL, *m = NULL;
28647dd1d1bSDag-Erling Smørgrav 	size_t len, required_siglen;
28747dd1d1bSDag-Erling Smørgrav 	unsigned long long smlen = 0, mlen = 0;
28847dd1d1bSDag-Erling Smørgrav 	int r, ret;
28947dd1d1bSDag-Erling Smørgrav 
29047dd1d1bSDag-Erling Smørgrav 	if (key == NULL ||
29147dd1d1bSDag-Erling Smørgrav 	    sshkey_type_plain(key->type) != KEY_XMSS ||
29247dd1d1bSDag-Erling Smørgrav 	    key->xmss_pk == NULL ||
29347dd1d1bSDag-Erling Smørgrav 	    sshkey_xmss_params(key) == NULL ||
294f374ba41SEd Maste 	    sig == NULL || siglen == 0)
29547dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
29647dd1d1bSDag-Erling Smørgrav 	if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
29747dd1d1bSDag-Erling Smørgrav 		return r;
298f374ba41SEd Maste 	if (dlen >= INT_MAX - required_siglen)
29947dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_INVALID_ARGUMENT;
30047dd1d1bSDag-Erling Smørgrav 
301f374ba41SEd Maste 	if ((b = sshbuf_from(sig, siglen)) == NULL)
30247dd1d1bSDag-Erling Smørgrav 		return SSH_ERR_ALLOC_FAIL;
30347dd1d1bSDag-Erling Smørgrav 	if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
30447dd1d1bSDag-Erling Smørgrav 	    (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
30547dd1d1bSDag-Erling Smørgrav 		goto out;
30647dd1d1bSDag-Erling Smørgrav 	if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
30747dd1d1bSDag-Erling Smørgrav 		r = SSH_ERR_KEY_TYPE_MISMATCH;
30847dd1d1bSDag-Erling Smørgrav 		goto out;
30947dd1d1bSDag-Erling Smørgrav 	}
31047dd1d1bSDag-Erling Smørgrav 	if (sshbuf_len(b) != 0) {
31147dd1d1bSDag-Erling Smørgrav 		r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
31247dd1d1bSDag-Erling Smørgrav 		goto out;
31347dd1d1bSDag-Erling Smørgrav 	}
31447dd1d1bSDag-Erling Smørgrav 	if (len != required_siglen) {
31547dd1d1bSDag-Erling Smørgrav 		r = SSH_ERR_INVALID_FORMAT;
31647dd1d1bSDag-Erling Smørgrav 		goto out;
31747dd1d1bSDag-Erling Smørgrav 	}
318f374ba41SEd Maste 	if (dlen >= SIZE_MAX - len) {
31947dd1d1bSDag-Erling Smørgrav 		r = SSH_ERR_INVALID_ARGUMENT;
32047dd1d1bSDag-Erling Smørgrav 		goto out;
32147dd1d1bSDag-Erling Smørgrav 	}
322f374ba41SEd Maste 	smlen = len + dlen;
32347dd1d1bSDag-Erling Smørgrav 	mlen = smlen;
32447dd1d1bSDag-Erling Smørgrav 	if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
32547dd1d1bSDag-Erling Smørgrav 		r = SSH_ERR_ALLOC_FAIL;
32647dd1d1bSDag-Erling Smørgrav 		goto out;
32747dd1d1bSDag-Erling Smørgrav 	}
32847dd1d1bSDag-Erling Smørgrav 	memcpy(sm, sigblob, len);
329f374ba41SEd Maste 	memcpy(sm+len, data, dlen);
33047dd1d1bSDag-Erling Smørgrav 	if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
33147dd1d1bSDag-Erling Smørgrav 	    key->xmss_pk, sshkey_xmss_params(key))) != 0) {
33219261079SEd Maste 		debug2_f("xmss_sign_open failed: %d", ret);
33347dd1d1bSDag-Erling Smørgrav 	}
334f374ba41SEd Maste 	if (ret != 0 || mlen != dlen) {
33547dd1d1bSDag-Erling Smørgrav 		r = SSH_ERR_SIGNATURE_INVALID;
33647dd1d1bSDag-Erling Smørgrav 		goto out;
33747dd1d1bSDag-Erling Smørgrav 	}
33847dd1d1bSDag-Erling Smørgrav 	/* XXX compare 'm' and 'data' ? */
33947dd1d1bSDag-Erling Smørgrav 	/* success */
34047dd1d1bSDag-Erling Smørgrav 	r = 0;
34147dd1d1bSDag-Erling Smørgrav  out:
34219261079SEd Maste 	if (sm != NULL)
34319261079SEd Maste 		freezero(sm, smlen);
34419261079SEd Maste 	if (m != NULL)
34519261079SEd Maste 		freezero(m, smlen);
34647dd1d1bSDag-Erling Smørgrav 	sshbuf_free(b);
34747dd1d1bSDag-Erling Smørgrav 	free(ktype);
34847dd1d1bSDag-Erling Smørgrav 	return r;
34947dd1d1bSDag-Erling Smørgrav }
350f374ba41SEd Maste 
351f374ba41SEd Maste static const struct sshkey_impl_funcs sshkey_xmss_funcs = {
352f374ba41SEd Maste 	/* .size = */		NULL,
353f374ba41SEd Maste 	/* .alloc = */		NULL,
354f374ba41SEd Maste 	/* .cleanup = */	ssh_xmss_cleanup,
355f374ba41SEd Maste 	/* .equal = */		ssh_xmss_equal,
356f374ba41SEd Maste 	/* .ssh_serialize_public = */ ssh_xmss_serialize_public,
357f374ba41SEd Maste 	/* .ssh_deserialize_public = */ ssh_xmss_deserialize_public,
358f374ba41SEd Maste 	/* .ssh_serialize_private = */ ssh_xmss_serialize_private,
359f374ba41SEd Maste 	/* .ssh_deserialize_private = */ ssh_xmss_deserialize_private,
360f374ba41SEd Maste 	/* .generate = */	sshkey_xmss_generate_private_key,
361f374ba41SEd Maste 	/* .copy_public = */	ssh_xmss_copy_public,
362f374ba41SEd Maste 	/* .sign = */		ssh_xmss_sign,
363f374ba41SEd Maste 	/* .verify = */		ssh_xmss_verify,
364f374ba41SEd Maste };
365f374ba41SEd Maste 
366f374ba41SEd Maste const struct sshkey_impl sshkey_xmss_impl = {
367f374ba41SEd Maste 	/* .name = */		"ssh-xmss@openssh.com",
368f374ba41SEd Maste 	/* .shortname = */	"XMSS",
369f374ba41SEd Maste 	/* .sigalg = */		NULL,
370f374ba41SEd Maste 	/* .type = */		KEY_XMSS,
371f374ba41SEd Maste 	/* .nid = */		0,
372f374ba41SEd Maste 	/* .cert = */		0,
373f374ba41SEd Maste 	/* .sigonly = */	0,
374f374ba41SEd Maste 	/* .keybits = */	256,
375f374ba41SEd Maste 	/* .funcs = */		&sshkey_xmss_funcs,
376f374ba41SEd Maste };
377f374ba41SEd Maste 
378f374ba41SEd Maste const struct sshkey_impl sshkey_xmss_cert_impl = {
379f374ba41SEd Maste 	/* .name = */		"ssh-xmss-cert-v01@openssh.com",
380f374ba41SEd Maste 	/* .shortname = */	"XMSS-CERT",
381f374ba41SEd Maste 	/* .sigalg = */		NULL,
382f374ba41SEd Maste 	/* .type = */		KEY_XMSS_CERT,
383f374ba41SEd Maste 	/* .nid = */		0,
384f374ba41SEd Maste 	/* .cert = */		1,
385f374ba41SEd Maste 	/* .sigonly = */	0,
386f374ba41SEd Maste 	/* .keybits = */	256,
387f374ba41SEd Maste 	/* .funcs = */		&sshkey_xmss_funcs,
388f374ba41SEd Maste };
38947dd1d1bSDag-Erling Smørgrav #endif /* WITH_XMSS */
390