File: | src/usr.bin/ssh/ssh/../ssh-ed25519.c |
Warning: | line 168, column 7 Although the value stored to 'ret' is used in the enclosing expression, the value is never actually read from 'ret' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: ssh-ed25519.c,v 1.19 2022/10/28 00:44:44 djm Exp $ */ |
2 | /* |
3 | * Copyright (c) 2013 Markus Friedl <markus@openbsd.org> |
4 | * |
5 | * Permission to use, copy, modify, and distribute this software for any |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. |
8 | * |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 | */ |
17 | #define SSHKEY_INTERNAL |
18 | #include <sys/types.h> |
19 | #include <limits.h> |
20 | |
21 | #include "crypto_api.h" |
22 | |
23 | #include <string.h> |
24 | #include <stdarg.h> |
25 | |
26 | #include "log.h" |
27 | #include "sshbuf.h" |
28 | #include "sshkey.h" |
29 | #include "ssherr.h" |
30 | #include "ssh.h" |
31 | |
32 | static void |
33 | ssh_ed25519_cleanup(struct sshkey *k) |
34 | { |
35 | freezero(k->ed25519_pk, ED25519_PK_SZ32U); |
36 | freezero(k->ed25519_sk, ED25519_SK_SZ64U); |
37 | k->ed25519_pk = NULL((void *)0); |
38 | k->ed25519_sk = NULL((void *)0); |
39 | } |
40 | |
41 | static int |
42 | ssh_ed25519_equal(const struct sshkey *a, const struct sshkey *b) |
43 | { |
44 | if (a->ed25519_pk == NULL((void *)0) || b->ed25519_pk == NULL((void *)0)) |
45 | return 0; |
46 | if (memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ32U) != 0) |
47 | return 0; |
48 | return 1; |
49 | } |
50 | |
51 | static int |
52 | ssh_ed25519_serialize_public(const struct sshkey *key, struct sshbuf *b, |
53 | enum sshkey_serialize_rep opts) |
54 | { |
55 | int r; |
56 | |
57 | if (key->ed25519_pk == NULL((void *)0)) |
58 | return SSH_ERR_INVALID_ARGUMENT-10; |
59 | if ((r = sshbuf_put_string(b, key->ed25519_pk, ED25519_PK_SZ32U)) != 0) |
60 | return r; |
61 | |
62 | return 0; |
63 | } |
64 | |
65 | static int |
66 | ssh_ed25519_serialize_private(const struct sshkey *key, struct sshbuf *b, |
67 | enum sshkey_serialize_rep opts) |
68 | { |
69 | int r; |
70 | |
71 | if ((r = sshbuf_put_string(b, key->ed25519_pk, ED25519_PK_SZ32U)) != 0 || |
72 | (r = sshbuf_put_string(b, key->ed25519_sk, ED25519_SK_SZ64U)) != 0) |
73 | return r; |
74 | |
75 | return 0; |
76 | } |
77 | |
78 | static int |
79 | ssh_ed25519_generate(struct sshkey *k, int bits) |
80 | { |
81 | if ((k->ed25519_pk = malloc(ED25519_PK_SZ32U)) == NULL((void *)0) || |
82 | (k->ed25519_sk = malloc(ED25519_SK_SZ64U)) == NULL((void *)0)) |
83 | return SSH_ERR_ALLOC_FAIL-2; |
84 | crypto_sign_ed25519_keypair(k->ed25519_pk, k->ed25519_sk); |
85 | return 0; |
86 | } |
87 | |
88 | static int |
89 | ssh_ed25519_copy_public(const struct sshkey *from, struct sshkey *to) |
90 | { |
91 | if (from->ed25519_pk == NULL((void *)0)) |
92 | return 0; /* XXX SSH_ERR_INTERNAL_ERROR ? */ |
93 | if ((to->ed25519_pk = malloc(ED25519_PK_SZ32U)) == NULL((void *)0)) |
94 | return SSH_ERR_ALLOC_FAIL-2; |
95 | memcpy(to->ed25519_pk, from->ed25519_pk, ED25519_PK_SZ32U); |
96 | return 0; |
97 | } |
98 | |
99 | static int |
100 | ssh_ed25519_deserialize_public(const char *ktype, struct sshbuf *b, |
101 | struct sshkey *key) |
102 | { |
103 | u_char *pk = NULL((void *)0); |
104 | size_t len = 0; |
105 | int r; |
106 | |
107 | if ((r = sshbuf_get_string(b, &pk, &len)) != 0) |
108 | return r; |
109 | if (len != ED25519_PK_SZ32U) { |
110 | freezero(pk, len); |
111 | return SSH_ERR_INVALID_FORMAT-4; |
112 | } |
113 | key->ed25519_pk = pk; |
114 | return 0; |
115 | } |
116 | |
117 | static int |
118 | ssh_ed25519_deserialize_private(const char *ktype, struct sshbuf *b, |
119 | struct sshkey *key) |
120 | { |
121 | int r; |
122 | size_t sklen = 0; |
123 | u_char *ed25519_sk = NULL((void *)0); |
124 | |
125 | if ((r = ssh_ed25519_deserialize_public(NULL((void *)0), b, key)) != 0) |
126 | goto out; |
127 | if ((r = sshbuf_get_string(b, &ed25519_sk, &sklen)) != 0) |
128 | goto out; |
129 | if (sklen != ED25519_SK_SZ64U) { |
130 | r = SSH_ERR_INVALID_FORMAT-4; |
131 | goto out; |
132 | } |
133 | key->ed25519_sk = ed25519_sk; |
134 | ed25519_sk = NULL((void *)0); /* transferred */ |
135 | /* success */ |
136 | r = 0; |
137 | out: |
138 | freezero(ed25519_sk, sklen); |
139 | return r; |
140 | } |
141 | |
142 | static int |
143 | ssh_ed25519_sign(struct sshkey *key, |
144 | u_char **sigp, size_t *lenp, |
145 | const u_char *data, size_t datalen, |
146 | const char *alg, const char *sk_provider, const char *sk_pin, u_int compat) |
147 | { |
148 | u_char *sig = NULL((void *)0); |
149 | size_t slen = 0, len; |
150 | unsigned long long smlen; |
151 | int r, ret; |
152 | struct sshbuf *b = NULL((void *)0); |
153 | |
154 | if (lenp != NULL((void *)0)) |
155 | *lenp = 0; |
156 | if (sigp != NULL((void *)0)) |
157 | *sigp = NULL((void *)0); |
158 | |
159 | if (key == NULL((void *)0) || |
160 | sshkey_type_plain(key->type) != KEY_ED25519 || |
161 | key->ed25519_sk == NULL((void *)0) || |
162 | datalen >= INT_MAX0x7fffffff - crypto_sign_ed25519_BYTES64U) |
163 | return SSH_ERR_INVALID_ARGUMENT-10; |
164 | smlen = slen = datalen + crypto_sign_ed25519_BYTES64U; |
165 | if ((sig = malloc(slen)) == NULL((void *)0)) |
166 | return SSH_ERR_ALLOC_FAIL-2; |
167 | |
168 | if ((ret = crypto_sign_ed25519(sig, &smlen, data, datalen, |
Although the value stored to 'ret' is used in the enclosing expression, the value is never actually read from 'ret' | |
169 | key->ed25519_sk)) != 0 || smlen <= datalen) { |
170 | r = SSH_ERR_INVALID_ARGUMENT-10; /* XXX better error? */ |
171 | goto out; |
172 | } |
173 | /* encode signature */ |
174 | if ((b = sshbuf_new()) == NULL((void *)0)) { |
175 | r = SSH_ERR_ALLOC_FAIL-2; |
176 | goto out; |
177 | } |
178 | if ((r = sshbuf_put_cstring(b, "ssh-ed25519")) != 0 || |
179 | (r = sshbuf_put_string(b, sig, smlen - datalen)) != 0) |
180 | goto out; |
181 | len = sshbuf_len(b); |
182 | if (sigp != NULL((void *)0)) { |
183 | if ((*sigp = malloc(len)) == NULL((void *)0)) { |
184 | r = SSH_ERR_ALLOC_FAIL-2; |
185 | goto out; |
186 | } |
187 | memcpy(*sigp, sshbuf_ptr(b), len); |
188 | } |
189 | if (lenp != NULL((void *)0)) |
190 | *lenp = len; |
191 | /* success */ |
192 | r = 0; |
193 | out: |
194 | sshbuf_free(b); |
195 | if (sig != NULL((void *)0)) |
196 | freezero(sig, slen); |
197 | |
198 | return r; |
199 | } |
200 | |
201 | static int |
202 | ssh_ed25519_verify(const struct sshkey *key, |
203 | const u_char *sig, size_t siglen, |
204 | const u_char *data, size_t dlen, const char *alg, u_int compat, |
205 | struct sshkey_sig_details **detailsp) |
206 | { |
207 | struct sshbuf *b = NULL((void *)0); |
208 | char *ktype = NULL((void *)0); |
209 | const u_char *sigblob; |
210 | u_char *sm = NULL((void *)0), *m = NULL((void *)0); |
211 | size_t len; |
212 | unsigned long long smlen = 0, mlen = 0; |
213 | int r, ret; |
214 | |
215 | if (key == NULL((void *)0) || |
216 | sshkey_type_plain(key->type) != KEY_ED25519 || |
217 | key->ed25519_pk == NULL((void *)0) || |
218 | dlen >= INT_MAX0x7fffffff - crypto_sign_ed25519_BYTES64U || |
219 | sig == NULL((void *)0) || siglen == 0) |
220 | return SSH_ERR_INVALID_ARGUMENT-10; |
221 | |
222 | if ((b = sshbuf_from(sig, siglen)) == NULL((void *)0)) |
223 | return SSH_ERR_ALLOC_FAIL-2; |
224 | if ((r = sshbuf_get_cstring(b, &ktype, NULL((void *)0))) != 0 || |
225 | (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) |
226 | goto out; |
227 | if (strcmp("ssh-ed25519", ktype) != 0) { |
228 | r = SSH_ERR_KEY_TYPE_MISMATCH-13; |
229 | goto out; |
230 | } |
231 | if (sshbuf_len(b) != 0) { |
232 | r = SSH_ERR_UNEXPECTED_TRAILING_DATA-23; |
233 | goto out; |
234 | } |
235 | if (len > crypto_sign_ed25519_BYTES64U) { |
236 | r = SSH_ERR_INVALID_FORMAT-4; |
237 | goto out; |
238 | } |
239 | if (dlen >= SIZE_MAX0xffffffffffffffffUL - len) { |
240 | r = SSH_ERR_INVALID_ARGUMENT-10; |
241 | goto out; |
242 | } |
243 | smlen = len + dlen; |
244 | mlen = smlen; |
245 | if ((sm = malloc(smlen)) == NULL((void *)0) || (m = malloc(mlen)) == NULL((void *)0)) { |
246 | r = SSH_ERR_ALLOC_FAIL-2; |
247 | goto out; |
248 | } |
249 | memcpy(sm, sigblob, len); |
250 | memcpy(sm+len, data, dlen); |
251 | if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, |
252 | key->ed25519_pk)) != 0) { |
253 | debug2_f("crypto_sign_ed25519_open failed: %d", ret)sshlog("/usr/src/usr.bin/ssh/ssh/../ssh-ed25519.c", __func__, 253, 1, SYSLOG_LEVEL_DEBUG2, ((void *)0), "crypto_sign_ed25519_open failed: %d" , ret); |
254 | } |
255 | if (ret != 0 || mlen != dlen) { |
256 | r = SSH_ERR_SIGNATURE_INVALID-21; |
257 | goto out; |
258 | } |
259 | /* XXX compare 'm' and 'data' ? */ |
260 | /* success */ |
261 | r = 0; |
262 | out: |
263 | if (sm != NULL((void *)0)) |
264 | freezero(sm, smlen); |
265 | if (m != NULL((void *)0)) |
266 | freezero(m, smlen); /* NB mlen may be invalid if r != 0 */ |
267 | sshbuf_free(b); |
268 | free(ktype); |
269 | return r; |
270 | } |
271 | |
272 | /* NB. not static; used by ED25519-SK */ |
273 | const struct sshkey_impl_funcs sshkey_ed25519_funcs = { |
274 | /* .size = */ NULL((void *)0), |
275 | /* .alloc = */ NULL((void *)0), |
276 | /* .cleanup = */ ssh_ed25519_cleanup, |
277 | /* .equal = */ ssh_ed25519_equal, |
278 | /* .ssh_serialize_public = */ ssh_ed25519_serialize_public, |
279 | /* .ssh_deserialize_public = */ ssh_ed25519_deserialize_public, |
280 | /* .ssh_serialize_private = */ ssh_ed25519_serialize_private, |
281 | /* .ssh_deserialize_private = */ ssh_ed25519_deserialize_private, |
282 | /* .generate = */ ssh_ed25519_generate, |
283 | /* .copy_public = */ ssh_ed25519_copy_public, |
284 | /* .sign = */ ssh_ed25519_sign, |
285 | /* .verify = */ ssh_ed25519_verify, |
286 | }; |
287 | |
288 | const struct sshkey_impl sshkey_ed25519_impl = { |
289 | /* .name = */ "ssh-ed25519", |
290 | /* .shortname = */ "ED25519", |
291 | /* .sigalg = */ NULL((void *)0), |
292 | /* .type = */ KEY_ED25519, |
293 | /* .nid = */ 0, |
294 | /* .cert = */ 0, |
295 | /* .sigonly = */ 0, |
296 | /* .keybits = */ 256, |
297 | /* .funcs = */ &sshkey_ed25519_funcs, |
298 | }; |
299 | |
300 | const struct sshkey_impl sshkey_ed25519_cert_impl = { |
301 | /* .name = */ "ssh-ed25519-cert-v01@openssh.com", |
302 | /* .shortname = */ "ED25519-CERT", |
303 | /* .sigalg = */ NULL((void *)0), |
304 | /* .type = */ KEY_ED25519_CERT, |
305 | /* .nid = */ 0, |
306 | /* .cert = */ 1, |
307 | /* .sigonly = */ 0, |
308 | /* .keybits = */ 256, |
309 | /* .funcs = */ &sshkey_ed25519_funcs, |
310 | }; |