summaryrefslogtreecommitdiff
path: root/ssh-xmss.c
diff options
context:
space:
mode:
authormarkus@openbsd.org <markus@openbsd.org>2018-02-23 15:58:37 +0000
committerDamien Miller <djm@mindrot.org>2018-02-26 11:40:41 +1100
commit1b11ea7c58cd5c59838b5fa574cd456d6047b2d4 (patch)
tree7e96cb41b5234b9d327f7c8f41392f09aed0994e /ssh-xmss.c
parent7d330a1ac02076de98cfc8fda05353d57b603755 (diff)
upstream: Add experimental support for PQC XMSS keys (Extended
Hash-Based Signatures) The code is not compiled in by default (see WITH_XMSS in Makefile.inc) Joint work with stefan-lukas_gazdag at genua.eu See https://tools.ietf.org/html/draft-irtf-cfrg-xmss-hash-based-signatures-12 ok djm@ OpenBSD-Commit-ID: ef3eccb96762a5d6f135d7daeef608df7776a7ac
Diffstat (limited to 'ssh-xmss.c')
-rw-r--r--ssh-xmss.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/ssh-xmss.c b/ssh-xmss.c
new file mode 100644
index 000000000..d9dafd762
--- /dev/null
+++ b/ssh-xmss.c
@@ -0,0 +1,188 @@
1/* $OpenBSD: ssh-xmss.c,v 1.1 2018/02/23 15:58:38 markus Exp $*/
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
35int
36ssh_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;
62 if ((r = sshkey_xmss_get_state(key, error)) != 0)
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:
90 if ((ret = sshkey_xmss_update_state(key, error)) != 0) {
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);
103 if (sig != NULL) {
104 explicit_bzero(sig, slen);
105 free(sig);
106 }
107
108 return r;
109}
110
111int
112ssh_xmss_verify(const struct sshkey *key,
113 const u_char *signature, size_t signaturelen,
114 const u_char *data, size_t datalen, u_int compat)
115{
116 struct sshbuf *b = NULL;
117 char *ktype = NULL;
118 const u_char *sigblob;
119 u_char *sm = NULL, *m = NULL;
120 size_t len, required_siglen;
121 unsigned long long smlen = 0, mlen = 0;
122 int r, ret;
123
124 if (key == NULL ||
125 sshkey_type_plain(key->type) != KEY_XMSS ||
126 key->xmss_pk == NULL ||
127 sshkey_xmss_params(key) == NULL ||
128 signature == NULL || signaturelen == 0)
129 return SSH_ERR_INVALID_ARGUMENT;
130 if ((r = sshkey_xmss_siglen(key, &required_siglen)) != 0)
131 return r;
132 if (datalen >= INT_MAX - required_siglen)
133 return SSH_ERR_INVALID_ARGUMENT;
134
135 if ((b = sshbuf_from(signature, signaturelen)) == NULL)
136 return SSH_ERR_ALLOC_FAIL;
137 if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 ||
138 (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0)
139 goto out;
140 if (strcmp("ssh-xmss@openssh.com", ktype) != 0) {
141 r = SSH_ERR_KEY_TYPE_MISMATCH;
142 goto out;
143 }
144 if (sshbuf_len(b) != 0) {
145 r = SSH_ERR_UNEXPECTED_TRAILING_DATA;
146 goto out;
147 }
148 if (len != required_siglen) {
149 r = SSH_ERR_INVALID_FORMAT;
150 goto out;
151 }
152 if (datalen >= SIZE_MAX - len) {
153 r = SSH_ERR_INVALID_ARGUMENT;
154 goto out;
155 }
156 smlen = len + datalen;
157 mlen = smlen;
158 if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) {
159 r = SSH_ERR_ALLOC_FAIL;
160 goto out;
161 }
162 memcpy(sm, sigblob, len);
163 memcpy(sm+len, data, datalen);
164 if ((ret = xmss_sign_open(m, &mlen, sm, smlen,
165 key->xmss_pk, sshkey_xmss_params(key))) != 0) {
166 debug2("%s: crypto_sign_xmss_open failed: %d",
167 __func__, ret);
168 }
169 if (ret != 0 || mlen != datalen) {
170 r = SSH_ERR_SIGNATURE_INVALID;
171 goto out;
172 }
173 /* XXX compare 'm' and 'data' ? */
174 /* success */
175 r = 0;
176 out:
177 if (sm != NULL) {
178 explicit_bzero(sm, smlen);
179 free(sm);
180 }
181 if (m != NULL) {
182 explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */
183 free(m);
184 }
185 sshbuf_free(b);
186 free(ktype);
187 return r;
188}