Annotation of src/usr.bin/ssh/ssh-xmss.c, Revision 1.4
1.4 ! dtucker 1: /* $OpenBSD: ssh-xmss.c,v 1.3 2020/10/18 11:32:02 djm 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:
22: #include <string.h>
23: #include <stdarg.h>
24: #include <unistd.h>
25:
26: #include "log.h"
27: #include "sshbuf.h"
28: #include "sshkey.h"
29: #include "sshkey-xmss.h"
30: #include "ssherr.h"
31: #include "ssh.h"
32:
33: #include "xmss_fast.h"
34:
35: int
36: ssh_xmss_sign(const struct sshkey *key, u_char **sigp, size_t *lenp,
37: const u_char *data, size_t datalen, u_int compat)
38: {
39: u_char *sig = NULL;
40: size_t slen = 0, len = 0, required_siglen;
41: unsigned long long smlen;
42: int r, ret;
43: struct sshbuf *b = NULL;
44:
45: if (lenp != NULL)
46: *lenp = 0;
47: if (sigp != NULL)
48: *sigp = NULL;
49:
50: if (key == NULL ||
51: sshkey_type_plain(key->type) != KEY_XMSS ||
52: key->xmss_sk == NULL ||
53: sshkey_xmss_params(key) == NULL)
54: return SSH_ERR_INVALID_ARGUMENT;
55: if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
56: return r;
57: if (datalen >= INT_MAX - required_siglen)
58: return SSH_ERR_INVALID_ARGUMENT;
59: smlen = slen = datalen + required_siglen;
60: if ((sig = malloc(slen)) == NULL)
61: return SSH_ERR_ALLOC_FAIL;
1.4 ! dtucker 62: if ((r = sshkey_xmss_get_state(key, 1)) != 0)
1.1 markus 63: goto out;
64: if ((ret = xmss_sign(key->xmss_sk, sshkey_xmss_bds_state(key), sig, &smlen,
65: data, datalen, sshkey_xmss_params(key))) != 0 || smlen <= datalen) {
66: r = SSH_ERR_INVALID_ARGUMENT; /* XXX better error? */
67: goto out;
68: }
69: /* encode signature */
70: if ((b = sshbuf_new()) == NULL) {
71: r = SSH_ERR_ALLOC_FAIL;
72: goto out;
73: }
74: if ((r = sshbuf_put_cstring(b, "ssh-xmss@openssh.com")) != 0 ||
75: (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0)
76: goto out;
77: len = sshbuf_len(b);
78: if (sigp != NULL) {
79: if ((*sigp = malloc(len)) == NULL) {
80: r = SSH_ERR_ALLOC_FAIL;
81: goto out;
82: }
83: memcpy(*sigp, sshbuf_ptr(b), len);
84: }
85: if (lenp != NULL)
86: *lenp = len;
87: /* success */
88: r = 0;
89: out:
1.4 ! dtucker 90: if ((ret = sshkey_xmss_update_state(key, 1)) != 0) {
1.1 markus 91: /* discard signature since we cannot update the state */
92: if (r == 0 && sigp != NULL && *sigp != NULL) {
93: explicit_bzero(*sigp, len);
94: free(*sigp);
95: }
96: if (sigp != NULL)
97: *sigp = NULL;
98: if (lenp != NULL)
99: *lenp = 0;
100: r = ret;
101: }
102: sshbuf_free(b);
1.2 jsg 103: if (sig != NULL)
104: freezero(sig, slen);
1.1 markus 105:
106: return r;
107: }
108:
109: int
110: ssh_xmss_verify(const struct sshkey *key,
111: const u_char *signature, size_t signaturelen,
112: const u_char *data, size_t datalen, u_int compat)
113: {
114: struct sshbuf *b = NULL;
115: char *ktype = NULL;
116: const u_char *sigblob;
117: u_char *sm = NULL, *m = NULL;
118: size_t len, required_siglen;
119: unsigned long long smlen = 0, mlen = 0;
120: int r, ret;
121:
122: if (key == NULL ||
123: sshkey_type_plain(key->type) != KEY_XMSS ||
124: key->xmss_pk == NULL ||
125: sshkey_xmss_params(key) == NULL ||
126: signature == NULL || signaturelen == 0)
127: return SSH_ERR_INVALID_ARGUMENT;
128: if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
129: return r;
130: if (datalen >= INT_MAX - required_siglen)
131: return SSH_ERR_INVALID_ARGUMENT;
132:
133: if ((b = sshbuf_from(signature, signaturelen)) == NULL)
134: return SSH_ERR_ALLOC_FAIL;
135: if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
136: (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
137: goto out;
138: if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
139: r = SSH_ERR_KEY_TYPE_MISMATCH;
140: goto out;
141: }
142: if (sshbuf_len(b) != 0) {
143: r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
144: goto out;
145: }
146: if (len != required_siglen) {
147: r = SSH_ERR_INVALID_FORMAT;
148: goto out;
149: }
150: if (datalen >= SIZE_MAX - len) {
151: r = SSH_ERR_INVALID_ARGUMENT;
152: goto out;
153: }
154: smlen = len + datalen;
155: mlen = smlen;
156: if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
157: r = SSH_ERR_ALLOC_FAIL;
158: goto out;
159: }
160: memcpy(sm, sigblob, len);
161: memcpy(sm+len, data, datalen);
162: if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
163: key->xmss_pk, sshkey_xmss_params(key))) != 0) {
1.3 djm 164: debug2_f("xmss_sign_open failed: %d", ret);
1.1 markus 165: }
166: if (ret != 0 || mlen != datalen) {
167: r = SSH_ERR_SIGNATURE_INVALID;
168: goto out;
169: }
170: /* XXX compare 'm' and 'data' ? */
171: /* success */
172: r = 0;
173: out:
1.2 jsg 174: if (sm != NULL)
175: freezero(sm, smlen);
176: if (m != NULL)
177: freezero(m, smlen);
1.1 markus 178: sshbuf_free(b);
179: free(ktype);
180: return r;
181: }