1*a2c931d9Sdjm /* $OpenBSD: ssh-xmss.c,v 1.14 2022/10/28 00:44:44 djm Exp $*/
2a6be8e7cSmarkus /*
3a6be8e7cSmarkus * Copyright (c) 2017 Stefan-Lukas Gazdag.
4a6be8e7cSmarkus * Copyright (c) 2017 Markus Friedl.
5a6be8e7cSmarkus *
6a6be8e7cSmarkus * Permission to use, copy, modify, and distribute this software for any
7a6be8e7cSmarkus * purpose with or without fee is hereby granted, provided that the above
8a6be8e7cSmarkus * copyright notice and this permission notice appear in all copies.
9a6be8e7cSmarkus *
10a6be8e7cSmarkus * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11a6be8e7cSmarkus * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12a6be8e7cSmarkus * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13a6be8e7cSmarkus * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14a6be8e7cSmarkus * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15a6be8e7cSmarkus * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16a6be8e7cSmarkus * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17a6be8e7cSmarkus */
18a6be8e7cSmarkus #define SSHKEY_INTERNAL
19a6be8e7cSmarkus #include <sys/types.h>
20a6be8e7cSmarkus #include <limits.h>
21a6be8e7cSmarkus
22ac635a03Smillert #include <stdlib.h>
23a6be8e7cSmarkus #include <string.h>
24a6be8e7cSmarkus #include <stdarg.h>
25ac635a03Smillert #include <stdint.h>
26a6be8e7cSmarkus #include <unistd.h>
27a6be8e7cSmarkus
28a6be8e7cSmarkus #include "log.h"
29a6be8e7cSmarkus #include "sshbuf.h"
30a6be8e7cSmarkus #include "sshkey.h"
31a6be8e7cSmarkus #include "sshkey-xmss.h"
32a6be8e7cSmarkus #include "ssherr.h"
33a6be8e7cSmarkus #include "ssh.h"
34a6be8e7cSmarkus
35a6be8e7cSmarkus #include "xmss_fast.h"
36a6be8e7cSmarkus
379c1667dbSdjm static void
ssh_xmss_cleanup(struct sshkey * k)389c1667dbSdjm ssh_xmss_cleanup(struct sshkey *k)
399c1667dbSdjm {
409c1667dbSdjm freezero(k->xmss_pk, sshkey_xmss_pklen(k));
419c1667dbSdjm freezero(k->xmss_sk, sshkey_xmss_sklen(k));
429c1667dbSdjm sshkey_xmss_free_state(k);
439c1667dbSdjm free(k->xmss_name);
449c1667dbSdjm free(k->xmss_filename);
459c1667dbSdjm k->xmss_pk = NULL;
469c1667dbSdjm k->xmss_sk = NULL;
479c1667dbSdjm k->xmss_name = NULL;
489c1667dbSdjm k->xmss_filename = NULL;
499c1667dbSdjm }
509c1667dbSdjm
51712f5ecfSdjm static int
ssh_xmss_equal(const struct sshkey * a,const struct sshkey * b)52712f5ecfSdjm ssh_xmss_equal(const struct sshkey *a, const struct sshkey *b)
53712f5ecfSdjm {
54712f5ecfSdjm if (a->xmss_pk == NULL || b->xmss_pk == NULL)
55712f5ecfSdjm return 0;
56712f5ecfSdjm if (sshkey_xmss_pklen(a) != sshkey_xmss_pklen(b))
57712f5ecfSdjm return 0;
58712f5ecfSdjm if (memcmp(a->xmss_pk, b->xmss_pk, sshkey_xmss_pklen(a)) != 0)
59712f5ecfSdjm return 0;
60712f5ecfSdjm return 1;
61712f5ecfSdjm }
62712f5ecfSdjm
63eefcf659Sdjm static int
ssh_xmss_serialize_public(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)64eefcf659Sdjm ssh_xmss_serialize_public(const struct sshkey *key, struct sshbuf *b,
65c8d92406Sdjm enum sshkey_serialize_rep opts)
66eefcf659Sdjm {
67eefcf659Sdjm int r;
68eefcf659Sdjm
69eefcf659Sdjm if (key->xmss_name == NULL || key->xmss_pk == NULL ||
70eefcf659Sdjm sshkey_xmss_pklen(key) == 0)
71eefcf659Sdjm return SSH_ERR_INVALID_ARGUMENT;
72c8d92406Sdjm if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
73eefcf659Sdjm (r = sshbuf_put_string(b, key->xmss_pk,
74eefcf659Sdjm sshkey_xmss_pklen(key))) != 0 ||
75eefcf659Sdjm (r = sshkey_xmss_serialize_pk_info(key, b, opts)) != 0)
76eefcf659Sdjm return r;
77eefcf659Sdjm
78eefcf659Sdjm return 0;
79eefcf659Sdjm }
80eefcf659Sdjm
810d39f001Sdjm static int
ssh_xmss_serialize_private(const struct sshkey * key,struct sshbuf * b,enum sshkey_serialize_rep opts)82d03db38bSdjm ssh_xmss_serialize_private(const struct sshkey *key, struct sshbuf *b,
83d03db38bSdjm enum sshkey_serialize_rep opts)
84d03db38bSdjm {
85d03db38bSdjm int r;
86d03db38bSdjm
87d03db38bSdjm if (key->xmss_name == NULL)
88d03db38bSdjm return SSH_ERR_INVALID_ARGUMENT;
89d03db38bSdjm /* Note: can't reuse ssh_xmss_serialize_public because of sk order */
90d03db38bSdjm if ((r = sshbuf_put_cstring(b, key->xmss_name)) != 0 ||
91d03db38bSdjm (r = sshbuf_put_string(b, key->xmss_pk,
92d03db38bSdjm sshkey_xmss_pklen(key))) != 0 ||
93d03db38bSdjm (r = sshbuf_put_string(b, key->xmss_sk,
94d03db38bSdjm sshkey_xmss_sklen(key))) != 0 ||
95d03db38bSdjm (r = sshkey_xmss_serialize_state_opt(key, b, opts)) != 0)
96d03db38bSdjm return r;
97d03db38bSdjm
98d03db38bSdjm return 0;
99d03db38bSdjm }
100d03db38bSdjm
101d03db38bSdjm static int
ssh_xmss_copy_public(const struct sshkey * from,struct sshkey * to)1020d39f001Sdjm ssh_xmss_copy_public(const struct sshkey *from, struct sshkey *to)
1030d39f001Sdjm {
1040d39f001Sdjm int r = SSH_ERR_INTERNAL_ERROR;
1050d39f001Sdjm u_int32_t left;
1060d39f001Sdjm size_t pklen;
1070d39f001Sdjm
1080d39f001Sdjm if ((r = sshkey_xmss_init(to, from->xmss_name)) != 0)
1090d39f001Sdjm return r;
1100d39f001Sdjm if (from->xmss_pk == NULL)
1110d39f001Sdjm return 0; /* XXX SSH_ERR_INTERNAL_ERROR ? */
1120d39f001Sdjm
1130d39f001Sdjm if ((pklen = sshkey_xmss_pklen(from)) == 0 ||
1140d39f001Sdjm sshkey_xmss_pklen(to) != pklen)
1150d39f001Sdjm return SSH_ERR_INTERNAL_ERROR;
1160d39f001Sdjm if ((to->xmss_pk = malloc(pklen)) == NULL)
1170d39f001Sdjm return SSH_ERR_ALLOC_FAIL;
1180d39f001Sdjm memcpy(to->xmss_pk, from->xmss_pk, pklen);
1190d39f001Sdjm /* simulate number of signatures left on pubkey */
1200d39f001Sdjm left = sshkey_xmss_signatures_left(from);
1210d39f001Sdjm if (left)
1220d39f001Sdjm sshkey_xmss_enable_maxsign(to, left);
1230d39f001Sdjm return 0;
1240d39f001Sdjm }
1250d39f001Sdjm
126c8d92406Sdjm static int
ssh_xmss_deserialize_public(const char * ktype,struct sshbuf * b,struct sshkey * key)127c8d92406Sdjm ssh_xmss_deserialize_public(const char *ktype, struct sshbuf *b,
128c8d92406Sdjm struct sshkey *key)
129c8d92406Sdjm {
130c8d92406Sdjm size_t len = 0;
131c8d92406Sdjm char *xmss_name = NULL;
132c8d92406Sdjm u_char *pk = NULL;
133c8d92406Sdjm int ret = SSH_ERR_INTERNAL_ERROR;
134c8d92406Sdjm
135c8d92406Sdjm if ((ret = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0)
136c8d92406Sdjm goto out;
137c8d92406Sdjm if ((ret = sshkey_xmss_init(key, xmss_name)) != 0)
138c8d92406Sdjm goto out;
139c8d92406Sdjm if ((ret = sshbuf_get_string(b, &pk, &len)) != 0)
140c8d92406Sdjm goto out;
141c8d92406Sdjm if (len == 0 || len != sshkey_xmss_pklen(key)) {
142c8d92406Sdjm ret = SSH_ERR_INVALID_FORMAT;
143c8d92406Sdjm goto out;
144c8d92406Sdjm }
145c8d92406Sdjm key->xmss_pk = pk;
146c8d92406Sdjm pk = NULL;
147c8d92406Sdjm if (!sshkey_is_cert(key) &&
148c8d92406Sdjm (ret = sshkey_xmss_deserialize_pk_info(key, b)) != 0)
149c8d92406Sdjm goto out;
150c8d92406Sdjm /* success */
151c8d92406Sdjm ret = 0;
152c8d92406Sdjm out:
153c8d92406Sdjm free(xmss_name);
154c8d92406Sdjm freezero(pk, len);
155c8d92406Sdjm return ret;
156c8d92406Sdjm }
157c8d92406Sdjm
158c5c174faSdjm static int
ssh_xmss_deserialize_private(const char * ktype,struct sshbuf * b,struct sshkey * key)159*a2c931d9Sdjm ssh_xmss_deserialize_private(const char *ktype, struct sshbuf *b,
160*a2c931d9Sdjm struct sshkey *key)
161*a2c931d9Sdjm {
162*a2c931d9Sdjm int r;
163*a2c931d9Sdjm char *xmss_name = NULL;
164*a2c931d9Sdjm size_t pklen = 0, sklen = 0;
165*a2c931d9Sdjm u_char *xmss_pk = NULL, *xmss_sk = NULL;
166*a2c931d9Sdjm
167*a2c931d9Sdjm /* Note: can't reuse ssh_xmss_deserialize_public because of sk order */
168*a2c931d9Sdjm if ((r = sshbuf_get_cstring(b, &xmss_name, NULL)) != 0 ||
169*a2c931d9Sdjm (r = sshbuf_get_string(b, &xmss_pk, &pklen)) != 0 ||
170*a2c931d9Sdjm (r = sshbuf_get_string(b, &xmss_sk, &sklen)) != 0)
171*a2c931d9Sdjm goto out;
172*a2c931d9Sdjm if (!sshkey_is_cert(key) &&
173*a2c931d9Sdjm (r = sshkey_xmss_init(key, xmss_name)) != 0)
174*a2c931d9Sdjm goto out;
175*a2c931d9Sdjm if (pklen != sshkey_xmss_pklen(key) ||
176*a2c931d9Sdjm sklen != sshkey_xmss_sklen(key)) {
177*a2c931d9Sdjm r = SSH_ERR_INVALID_FORMAT;
178*a2c931d9Sdjm goto out;
179*a2c931d9Sdjm }
180*a2c931d9Sdjm key->xmss_pk = xmss_pk;
181*a2c931d9Sdjm key->xmss_sk = xmss_sk;
182*a2c931d9Sdjm xmss_pk = xmss_sk = NULL;
183*a2c931d9Sdjm /* optional internal state */
184*a2c931d9Sdjm if ((r = sshkey_xmss_deserialize_state_opt(key, b)) != 0)
185*a2c931d9Sdjm goto out;
186*a2c931d9Sdjm /* success */
187*a2c931d9Sdjm r = 0;
188*a2c931d9Sdjm out:
189*a2c931d9Sdjm free(xmss_name);
190*a2c931d9Sdjm freezero(xmss_pk, pklen);
191*a2c931d9Sdjm freezero(xmss_sk, sklen);
192*a2c931d9Sdjm return r;
193*a2c931d9Sdjm }
194*a2c931d9Sdjm
195*a2c931d9Sdjm 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)196c5c174faSdjm ssh_xmss_sign(struct sshkey *key,
197c5c174faSdjm u_char **sigp, size_t *lenp,
198c5c174faSdjm const u_char *data, size_t datalen,
199c5c174faSdjm const char *alg, const char *sk_provider, const char *sk_pin, u_int compat)
200a6be8e7cSmarkus {
201a6be8e7cSmarkus u_char *sig = NULL;
202a6be8e7cSmarkus size_t slen = 0, len = 0, required_siglen;
203a6be8e7cSmarkus unsigned long long smlen;
204a6be8e7cSmarkus int r, ret;
205a6be8e7cSmarkus struct sshbuf *b = NULL;
206a6be8e7cSmarkus
207a6be8e7cSmarkus if (lenp != NULL)
208a6be8e7cSmarkus *lenp = 0;
209a6be8e7cSmarkus if (sigp != NULL)
210a6be8e7cSmarkus *sigp = NULL;
211a6be8e7cSmarkus
212a6be8e7cSmarkus if (key == NULL ||
213a6be8e7cSmarkus sshkey_type_plain(key->type) != KEY_XMSS ||
214a6be8e7cSmarkus key->xmss_sk == NULL ||
215a6be8e7cSmarkus sshkey_xmss_params(key) == NULL)
216a6be8e7cSmarkus return SSH_ERR_INVALID_ARGUMENT;
217a6be8e7cSmarkus if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
218a6be8e7cSmarkus return r;
219a6be8e7cSmarkus if (datalen >= INT_MAX - required_siglen)
220a6be8e7cSmarkus return SSH_ERR_INVALID_ARGUMENT;
221a6be8e7cSmarkus smlen = slen = datalen + required_siglen;
222a6be8e7cSmarkus if ((sig = malloc(slen)) == NULL)
223a6be8e7cSmarkus return SSH_ERR_ALLOC_FAIL;
22479e62715Sdtucker if ((r = sshkey_xmss_get_state(key, 1)) != 0)
225a6be8e7cSmarkus goto out;
226a6be8e7cSmarkus if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen,
227a6be8e7cSmarkus data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) {
228a6be8e7cSmarkus r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
229a6be8e7cSmarkus goto out;
230a6be8e7cSmarkus }
231a6be8e7cSmarkus /* encode signature */
232a6be8e7cSmarkus if ((b = sshbuf_new()) == NULL) {
233a6be8e7cSmarkus r = SSH_ERR_ALLOC_FAIL;
234a6be8e7cSmarkus goto out;
235a6be8e7cSmarkus }
236a6be8e7cSmarkus if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 ||
237a6be8e7cSmarkus (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
238a6be8e7cSmarkus goto out;
239a6be8e7cSmarkus len = sshbuf_len(b);
240a6be8e7cSmarkus if (sigp != NULL) {
241a6be8e7cSmarkus if ((*sigp = malloc(len)) == NULL) {
242a6be8e7cSmarkus r = SSH_ERR_ALLOC_FAIL;
243a6be8e7cSmarkus goto out;
244a6be8e7cSmarkus }
245a6be8e7cSmarkus memcpy(*sigp, sshbuf_ptr(b), len);
246a6be8e7cSmarkus }
247a6be8e7cSmarkus if (lenp != NULL)
248a6be8e7cSmarkus *lenp = len;
249a6be8e7cSmarkus /* success */
250a6be8e7cSmarkus r = 0;
251a6be8e7cSmarkus out:
25279e62715Sdtucker if ((ret = sshkey_xmss_update_state(key, 1)) != 0) {
253a6be8e7cSmarkus /* discard signature since we cannot update the state */
254a6be8e7cSmarkus if (r == 0 && sigp != NULL && *sigp != NULL) {
255a6be8e7cSmarkus explicit_bzero(*sigp, len);
256a6be8e7cSmarkus free(*sigp);
257a6be8e7cSmarkus }
258a6be8e7cSmarkus if (sigp != NULL)
259a6be8e7cSmarkus *sigp = NULL;
260a6be8e7cSmarkus if (lenp != NULL)
261a6be8e7cSmarkus *lenp = 0;
262a6be8e7cSmarkus r = ret;
263a6be8e7cSmarkus }
264a6be8e7cSmarkus sshbuf_free(b);
265c9831b39Sjsg if (sig != NULL)
266c9831b39Sjsg freezero(sig, slen);
267a6be8e7cSmarkus
268a6be8e7cSmarkus return r;
269a6be8e7cSmarkus }
270a6be8e7cSmarkus
271c5c174faSdjm 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)272a6be8e7cSmarkus ssh_xmss_verify(const struct sshkey *key,
273c5c174faSdjm const u_char *sig, size_t siglen,
274c5c174faSdjm const u_char *data, size_t dlen, const char *alg, u_int compat,
275c5c174faSdjm struct sshkey_sig_details **detailsp)
276a6be8e7cSmarkus {
277a6be8e7cSmarkus struct sshbuf *b = NULL;
278a6be8e7cSmarkus char *ktype = NULL;
279a6be8e7cSmarkus const u_char *sigblob;
280a6be8e7cSmarkus u_char *sm = NULL, *m = NULL;
281a6be8e7cSmarkus size_t len, required_siglen;
282a6be8e7cSmarkus unsigned long long smlen = 0, mlen = 0;
283a6be8e7cSmarkus int r, ret;
284a6be8e7cSmarkus
285a6be8e7cSmarkus if (key == NULL ||
286a6be8e7cSmarkus sshkey_type_plain(key->type) != KEY_XMSS ||
287a6be8e7cSmarkus key->xmss_pk == NULL ||
288a6be8e7cSmarkus sshkey_xmss_params(key) == NULL ||
289c5c174faSdjm sig == NULL || siglen == 0)
290a6be8e7cSmarkus return SSH_ERR_INVALID_ARGUMENT;
291a6be8e7cSmarkus if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
292a6be8e7cSmarkus return r;
293c5c174faSdjm if (dlen >= INT_MAX - required_siglen)
294a6be8e7cSmarkus return SSH_ERR_INVALID_ARGUMENT;
295a6be8e7cSmarkus
296c5c174faSdjm if ((b = sshbuf_from(sig, siglen)) == NULL)
297a6be8e7cSmarkus return SSH_ERR_ALLOC_FAIL;
298a6be8e7cSmarkus if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
299a6be8e7cSmarkus (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
300a6be8e7cSmarkus goto out;
301a6be8e7cSmarkus if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
302a6be8e7cSmarkus r = SSH_ERR_KEY_TYPE_MISMATCH;
303a6be8e7cSmarkus goto out;
304a6be8e7cSmarkus }
305a6be8e7cSmarkus if (sshbuf_len(b) != 0) {
306a6be8e7cSmarkus r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
307a6be8e7cSmarkus goto out;
308a6be8e7cSmarkus }
309a6be8e7cSmarkus if (len != required_siglen) {
310a6be8e7cSmarkus r = SSH_ERR_INVALID_FORMAT;
311a6be8e7cSmarkus goto out;
312a6be8e7cSmarkus }
313c5c174faSdjm if (dlen >= SIZE_MAX - len) {
314a6be8e7cSmarkus r = SSH_ERR_INVALID_ARGUMENT;
315a6be8e7cSmarkus goto out;
316a6be8e7cSmarkus }
317c5c174faSdjm smlen = len + dlen;
318a6be8e7cSmarkus mlen = smlen;
319a6be8e7cSmarkus if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
320a6be8e7cSmarkus r = SSH_ERR_ALLOC_FAIL;
321a6be8e7cSmarkus goto out;
322a6be8e7cSmarkus }
323a6be8e7cSmarkus memcpy(sm, sigblob, len);
324c5c174faSdjm memcpy(sm+len, data, dlen);
325a6be8e7cSmarkus if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
326a6be8e7cSmarkus key->xmss_pk, sshkey_xmss_params(key))) != 0) {
32748e6b99dSdjm debug2_f("xmss_sign_open failed: %d", ret);
328a6be8e7cSmarkus }
329c5c174faSdjm if (ret != 0 || mlen != dlen) {
330a6be8e7cSmarkus r = SSH_ERR_SIGNATURE_INVALID;
331a6be8e7cSmarkus goto out;
332a6be8e7cSmarkus }
333a6be8e7cSmarkus /* XXX compare 'm' and 'data' ? */
334a6be8e7cSmarkus /* success */
335a6be8e7cSmarkus r = 0;
336a6be8e7cSmarkus out:
337c9831b39Sjsg if (sm != NULL)
338c9831b39Sjsg freezero(sm, smlen);
339c9831b39Sjsg if (m != NULL)
340c9831b39Sjsg freezero(m, smlen);
341a6be8e7cSmarkus sshbuf_free(b);
342a6be8e7cSmarkus free(ktype);
343a6be8e7cSmarkus return r;
344a6be8e7cSmarkus }
3459c1667dbSdjm
3469c1667dbSdjm static const struct sshkey_impl_funcs sshkey_xmss_funcs = {
3479c1667dbSdjm /* .size = */ NULL,
3489c1667dbSdjm /* .alloc = */ NULL,
3499c1667dbSdjm /* .cleanup = */ ssh_xmss_cleanup,
350712f5ecfSdjm /* .equal = */ ssh_xmss_equal,
351eefcf659Sdjm /* .ssh_serialize_public = */ ssh_xmss_serialize_public,
352c8d92406Sdjm /* .ssh_deserialize_public = */ ssh_xmss_deserialize_public,
353d03db38bSdjm /* .ssh_serialize_private = */ ssh_xmss_serialize_private,
354*a2c931d9Sdjm /* .ssh_deserialize_private = */ ssh_xmss_deserialize_private,
355b6025febSdjm /* .generate = */ sshkey_xmss_generate_private_key,
3560d39f001Sdjm /* .copy_public = */ ssh_xmss_copy_public,
357c5c174faSdjm /* .sign = */ ssh_xmss_sign,
358c5c174faSdjm /* .verify = */ ssh_xmss_verify,
3599c1667dbSdjm };
3609c1667dbSdjm
3619c1667dbSdjm const struct sshkey_impl sshkey_xmss_impl = {
3629c1667dbSdjm /* .name = */ "ssh-xmss@openssh.com",
3639c1667dbSdjm /* .shortname = */ "XMSS",
3649c1667dbSdjm /* .sigalg = */ NULL,
3659c1667dbSdjm /* .type = */ KEY_XMSS,
3669c1667dbSdjm /* .nid = */ 0,
3679c1667dbSdjm /* .cert = */ 0,
3689c1667dbSdjm /* .sigonly = */ 0,
3699c1667dbSdjm /* .keybits = */ 256,
3709c1667dbSdjm /* .funcs = */ &sshkey_xmss_funcs,
3719c1667dbSdjm };
3729c1667dbSdjm
3739c1667dbSdjm const struct sshkey_impl sshkey_xmss_cert_impl = {
3749c1667dbSdjm /* .name = */ "ssh-xmss-cert-v01@openssh.com",
3759c1667dbSdjm /* .shortname = */ "XMSS-CERT",
3769c1667dbSdjm /* .sigalg = */ NULL,
3779c1667dbSdjm /* .type = */ KEY_XMSS_CERT,
3789c1667dbSdjm /* .nid = */ 0,
3799c1667dbSdjm /* .cert = */ 1,
3809c1667dbSdjm /* .sigonly = */ 0,
3819c1667dbSdjm /* .keybits = */ 256,
3829c1667dbSdjm /* .funcs = */ &sshkey_xmss_funcs,
3839c1667dbSdjm };
384