Annotation of src/usr.bin/ssh/ssh-xmss.c, Revision 1.6
1.6 ! djm 1: /* $OpenBSD: ssh-xmss.c,v 1.5 2022/04/20 15:59:18 millert Exp $*/
1.1 markus 2: /*
3: * Copyright (c) 2017 Stefan-Lukas Gazdag.
4: * Copyright (c) 2017 Markus Friedl.
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18: #define SSHKEY_INTERNAL
19: #include <sys/types.h>
20: #include <limits.h>
21:
1.5 millert 22: #include <stdlib.h>
1.1 markus 23: #include <string.h>
24: #include <stdarg.h>
1.5 millert 25: #include <stdint.h>
1.1 markus 26: #include <unistd.h>
27:
28: #include "log.h"
29: #include "sshbuf.h"
30: #include "sshkey.h"
31: #include "sshkey-xmss.h"
32: #include "ssherr.h"
33: #include "ssh.h"
34:
35: #include "xmss_fast.h"
36:
1.6 ! djm 37: static void
! 38: ssh_xmss_cleanup(struct sshkey *k)
! 39: {
! 40: freezero(k->xmss_pk, sshkey_xmss_pklen(k));
! 41: freezero(k->xmss_sk, sshkey_xmss_sklen(k));
! 42: sshkey_xmss_free_state(k);
! 43: free(k->xmss_name);
! 44: free(k->xmss_filename);
! 45: k->xmss_pk = NULL;
! 46: k->xmss_sk = NULL;
! 47: k->xmss_name = NULL;
! 48: k->xmss_filename = NULL;
! 49: }
! 50:
1.1 markus 51: int
52: ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
53: const u_char *data, size_t datalen, u_int compat)
54: {
55: u_char *sig = NULL;
56: size_t slen = 0, len = 0, required_siglen;
57: unsigned long long smlen;
58: int r, ret;
59: struct sshbuf *b = NULL;
60:
61: if (lenp != NULL)
62: *lenp = 0;
63: if (sigp != NULL)
64: *sigp = NULL;
65:
66: if (key == NULL ||
67: sshkey_type_plain(key->type) != KEY_XMSS ||
68: key->xmss_sk == NULL ||
69: sshkey_xmss_params(key) == NULL)
70: return SSH_ERR_INVALID_ARGUMENT;
71: if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
72: return r;
73: if (datalen >= INT_MAX - required_siglen)
74: return SSH_ERR_INVALID_ARGUMENT;
75: smlen = slen = datalen + required_siglen;
76: if ((sig = malloc(slen)) == NULL)
77: return SSH_ERR_ALLOC_FAIL;
1.4 dtucker 78: if ((r = sshkey_xmss_get_state(key, 1)) != 0)
1.1 markus 79: goto out;
80: if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen,
81: data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) {
82: r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
83: goto out;
84: }
85: /* encode signature */
86: if ((b = sshbuf_new()) == NULL) {
87: r = SSH_ERR_ALLOC_FAIL;
88: goto out;
89: }
90: if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 ||
91: (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
92: goto out;
93: len = sshbuf_len(b);
94: if (sigp != NULL) {
95: if ((*sigp = malloc(len)) == NULL) {
96: r = SSH_ERR_ALLOC_FAIL;
97: goto out;
98: }
99: memcpy(*sigp, sshbuf_ptr(b), len);
100: }
101: if (lenp != NULL)
102: *lenp = len;
103: /* success */
104: r = 0;
105: out:
1.4 dtucker 106: if ((ret = sshkey_xmss_update_state(key, 1)) != 0) {
1.1 markus 107: /* discard signature since we cannot update the state */
108: if (r == 0 && sigp != NULL && *sigp != NULL) {
109: explicit_bzero(*sigp, len);
110: free(*sigp);
111: }
112: if (sigp != NULL)
113: *sigp = NULL;
114: if (lenp != NULL)
115: *lenp = 0;
116: r = ret;
117: }
118: sshbuf_free(b);
1.2 jsg 119: if (sig != NULL)
120: freezero(sig, slen);
1.1 markus 121:
122: return r;
123: }
124:
125: int
126: ssh_xmss_verify(const struct sshkey *key,
127: const u_char *signature, size_t signaturelen,
128: const u_char *data, size_t datalen, u_int compat)
129: {
130: struct sshbuf *b = NULL;
131: char *ktype = NULL;
132: const u_char *sigblob;
133: u_char *sm = NULL, *m = NULL;
134: size_t len, required_siglen;
135: unsigned long long smlen = 0, mlen = 0;
136: int r, ret;
137:
138: if (key == NULL ||
139: sshkey_type_plain(key->type) != KEY_XMSS ||
140: key->xmss_pk == NULL ||
141: sshkey_xmss_params(key) == NULL ||
142: signature == NULL || signaturelen == 0)
143: return SSH_ERR_INVALID_ARGUMENT;
144: if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
145: return r;
146: if (datalen >= INT_MAX - required_siglen)
147: return SSH_ERR_INVALID_ARGUMENT;
148:
149: if ((b = sshbuf_from(signature, signaturelen)) == NULL)
150: return SSH_ERR_ALLOC_FAIL;
151: if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
152: (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
153: goto out;
154: if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
155: r = SSH_ERR_KEY_TYPE_MISMATCH;
156: goto out;
157: }
158: if (sshbuf_len(b) != 0) {
159: r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
160: goto out;
161: }
162: if (len != required_siglen) {
163: r = SSH_ERR_INVALID_FORMAT;
164: goto out;
165: }
166: if (datalen >= SIZE_MAX - len) {
167: r = SSH_ERR_INVALID_ARGUMENT;
168: goto out;
169: }
170: smlen = len + datalen;
171: mlen = smlen;
172: if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
173: r = SSH_ERR_ALLOC_FAIL;
174: goto out;
175: }
176: memcpy(sm, sigblob, len);
177: memcpy(sm+len, data, datalen);
178: if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
179: key->xmss_pk, sshkey_xmss_params(key))) != 0) {
1.3 djm 180: debug2_f("xmss_sign_open failed: %d", ret);
1.1 markus 181: }
182: if (ret != 0 || mlen != datalen) {
183: r = SSH_ERR_SIGNATURE_INVALID;
184: goto out;
185: }
186: /* XXX compare 'm' and 'data' ? */
187: /* success */
188: r = 0;
189: out:
1.2 jsg 190: if (sm != NULL)
191: freezero(sm, smlen);
192: if (m != NULL)
193: freezero(m, smlen);
1.1 markus 194: sshbuf_free(b);
195: free(ktype);
196: return r;
197: }
1.6 ! djm 198:
! 199: static const struct sshkey_impl_funcs sshkey_xmss_funcs = {
! 200: /* .size = */ NULL,
! 201: /* .alloc = */ NULL,
! 202: /* .cleanup = */ ssh_xmss_cleanup,
! 203: };
! 204:
! 205: const struct sshkey_impl sshkey_xmss_impl = {
! 206: /* .name = */ "ssh-xmss@openssh.com",
! 207: /* .shortname = */ "XMSS",
! 208: /* .sigalg = */ NULL,
! 209: /* .type = */ KEY_XMSS,
! 210: /* .nid = */ 0,
! 211: /* .cert = */ 0,
! 212: /* .sigonly = */ 0,
! 213: /* .keybits = */ 256,
! 214: /* .funcs = */ &sshkey_xmss_funcs,
! 215: };
! 216:
! 217: const struct sshkey_impl sshkey_xmss_cert_impl = {
! 218: /* .name = */ "ssh-xmss-cert-v01@openssh.com",
! 219: /* .shortname = */ "XMSS-CERT",
! 220: /* .sigalg = */ NULL,
! 221: /* .type = */ KEY_XMSS_CERT,
! 222: /* .nid = */ 0,
! 223: /* .cert = */ 1,
! 224: /* .sigonly = */ 0,
! 225: /* .keybits = */ 256,
! 226: /* .funcs = */ &sshkey_xmss_funcs,
! 227: };