diff options
author | markus@openbsd.org <markus@openbsd.org> | 2015-01-19 20:16:15 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2015-01-20 09:19:39 +1100 |
commit | 57d10cbe861a235dd269c74fb2fe248469ecee9d (patch) | |
tree | c65deed24700490bd3b20300c4829d4d5466ff6d /kex.c | |
parent | 3fdc88a0def4f86aa88a5846ac079dc964c0546a (diff) |
upstream commit
adapt kex to sshbuf and struct ssh; ok djm@
Diffstat (limited to 'kex.c')
-rw-r--r-- | kex.c | 575 |
1 files changed, 338 insertions, 237 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.c,v 1.101 2015/01/19 20:07:45 markus Exp $ */ | 1 | /* $OpenBSD: kex.c,v 1.102 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -37,20 +37,22 @@ | |||
37 | #include <openssl/crypto.h> | 37 | #include <openssl/crypto.h> |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | #include "xmalloc.h" | ||
41 | #include "ssh2.h" | 40 | #include "ssh2.h" |
42 | #include "buffer.h" | ||
43 | #include "packet.h" | 41 | #include "packet.h" |
44 | #include "compat.h" | 42 | #include "compat.h" |
45 | #include "cipher.h" | 43 | #include "cipher.h" |
46 | #include "key.h" | 44 | #include "sshkey.h" |
47 | #include "kex.h" | 45 | #include "kex.h" |
48 | #include "log.h" | 46 | #include "log.h" |
49 | #include "mac.h" | 47 | #include "mac.h" |
50 | #include "match.h" | 48 | #include "match.h" |
49 | #include "misc.h" | ||
51 | #include "dispatch.h" | 50 | #include "dispatch.h" |
52 | #include "monitor.h" | 51 | #include "monitor.h" |
53 | #include "roaming.h" | 52 | #include "roaming.h" |
53 | |||
54 | #include "ssherr.h" | ||
55 | #include "sshbuf.h" | ||
54 | #include "digest.h" | 56 | #include "digest.h" |
55 | 57 | ||
56 | #if OPENSSL_VERSION_NUMBER >= 0x00907000L | 58 | #if OPENSSL_VERSION_NUMBER >= 0x00907000L |
@@ -62,12 +64,12 @@ extern const EVP_MD *evp_ssh_sha256(void); | |||
62 | #endif | 64 | #endif |
63 | 65 | ||
64 | /* prototype */ | 66 | /* prototype */ |
65 | static void kex_kexinit_finish(Kex *); | 67 | static int kex_choose_conf(struct ssh *); |
66 | static void kex_choose_conf(Kex *); | 68 | static int kex_input_newkeys(int, u_int32_t, void *); |
67 | 69 | ||
68 | struct kexalg { | 70 | struct kexalg { |
69 | char *name; | 71 | char *name; |
70 | int type; | 72 | u_int type; |
71 | int ec_nid; | 73 | int ec_nid; |
72 | int hash_alg; | 74 | int hash_alg; |
73 | }; | 75 | }; |
@@ -99,7 +101,7 @@ static const struct kexalg kexalgs[] = { | |||
99 | char * | 101 | char * |
100 | kex_alg_list(char sep) | 102 | kex_alg_list(char sep) |
101 | { | 103 | { |
102 | char *ret = NULL; | 104 | char *ret = NULL, *tmp; |
103 | size_t nlen, rlen = 0; | 105 | size_t nlen, rlen = 0; |
104 | const struct kexalg *k; | 106 | const struct kexalg *k; |
105 | 107 | ||
@@ -107,7 +109,11 @@ kex_alg_list(char sep) | |||
107 | if (ret != NULL) | 109 | if (ret != NULL) |
108 | ret[rlen++] = sep; | 110 | ret[rlen++] = sep; |
109 | nlen = strlen(k->name); | 111 | nlen = strlen(k->name); |
110 | ret = xrealloc(ret, 1, rlen + nlen + 2); | 112 | if ((tmp = realloc(ret, rlen + nlen + 2)) == NULL) { |
113 | free(ret); | ||
114 | return NULL; | ||
115 | } | ||
116 | ret = tmp; | ||
111 | memcpy(ret + rlen, k->name, nlen + 1); | 117 | memcpy(ret + rlen, k->name, nlen + 1); |
112 | rlen += nlen; | 118 | rlen += nlen; |
113 | } | 119 | } |
@@ -134,7 +140,8 @@ kex_names_valid(const char *names) | |||
134 | 140 | ||
135 | if (names == NULL || strcmp(names, "") == 0) | 141 | if (names == NULL || strcmp(names, "") == 0) |
136 | return 0; | 142 | return 0; |
137 | s = cp = xstrdup(names); | 143 | if ((s = cp = strdup(names)) == NULL) |
144 | return 0; | ||
138 | for ((p = strsep(&cp, ",")); p && *p != '\0'; | 145 | for ((p = strsep(&cp, ",")); p && *p != '\0'; |
139 | (p = strsep(&cp, ","))) { | 146 | (p = strsep(&cp, ","))) { |
140 | if (kex_alg_by_name(p) == NULL) { | 147 | if (kex_alg_by_name(p) == NULL) { |
@@ -149,56 +156,75 @@ kex_names_valid(const char *names) | |||
149 | } | 156 | } |
150 | 157 | ||
151 | /* put algorithm proposal into buffer */ | 158 | /* put algorithm proposal into buffer */ |
152 | static void | 159 | int |
153 | kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) | 160 | kex_prop2buf(struct sshbuf *b, char *proposal[PROPOSAL_MAX]) |
154 | { | 161 | { |
155 | u_int i; | 162 | u_int i; |
163 | int r; | ||
164 | |||
165 | sshbuf_reset(b); | ||
156 | 166 | ||
157 | buffer_clear(b); | ||
158 | /* | 167 | /* |
159 | * add a dummy cookie, the cookie will be overwritten by | 168 | * add a dummy cookie, the cookie will be overwritten by |
160 | * kex_send_kexinit(), each time a kexinit is set | 169 | * kex_send_kexinit(), each time a kexinit is set |
161 | */ | 170 | */ |
162 | for (i = 0; i < KEX_COOKIE_LEN; i++) | 171 | for (i = 0; i < KEX_COOKIE_LEN; i++) { |
163 | buffer_put_char(b, 0); | 172 | if ((r = sshbuf_put_u8(b, 0)) != 0) |
164 | for (i = 0; i < PROPOSAL_MAX; i++) | 173 | return r; |
165 | buffer_put_cstring(b, proposal[i]); | 174 | } |
166 | buffer_put_char(b, 0); /* first_kex_packet_follows */ | 175 | for (i = 0; i < PROPOSAL_MAX; i++) { |
167 | buffer_put_int(b, 0); /* uint32 reserved */ | 176 | if ((r = sshbuf_put_cstring(b, proposal[i])) != 0) |
177 | return r; | ||
178 | } | ||
179 | if ((r = sshbuf_put_u8(b, 0)) != 0 || /* first_kex_packet_follows */ | ||
180 | (r = sshbuf_put_u32(b, 0)) != 0) /* uint32 reserved */ | ||
181 | return r; | ||
182 | return 0; | ||
168 | } | 183 | } |
169 | 184 | ||
170 | /* parse buffer and return algorithm proposal */ | 185 | /* parse buffer and return algorithm proposal */ |
171 | static char ** | 186 | int |
172 | kex_buf2prop(Buffer *raw, int *first_kex_follows) | 187 | kex_buf2prop(struct sshbuf *raw, int *first_kex_follows, char ***propp) |
173 | { | 188 | { |
174 | Buffer b; | 189 | struct sshbuf *b = NULL; |
190 | u_char v; | ||
175 | u_int i; | 191 | u_int i; |
176 | char **proposal; | 192 | char **proposal = NULL; |
177 | 193 | int r; | |
178 | proposal = xcalloc(PROPOSAL_MAX, sizeof(char *)); | 194 | |
179 | 195 | *propp = NULL; | |
180 | buffer_init(&b); | 196 | if ((proposal = calloc(PROPOSAL_MAX, sizeof(char *))) == NULL) |
181 | buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); | 197 | return SSH_ERR_ALLOC_FAIL; |
182 | /* skip cookie */ | 198 | if ((b = sshbuf_fromb(raw)) == NULL) { |
183 | for (i = 0; i < KEX_COOKIE_LEN; i++) | 199 | r = SSH_ERR_ALLOC_FAIL; |
184 | buffer_get_char(&b); | 200 | goto out; |
201 | } | ||
202 | if ((r = sshbuf_consume(b, KEX_COOKIE_LEN)) != 0) /* skip cookie */ | ||
203 | goto out; | ||
185 | /* extract kex init proposal strings */ | 204 | /* extract kex init proposal strings */ |
186 | for (i = 0; i < PROPOSAL_MAX; i++) { | 205 | for (i = 0; i < PROPOSAL_MAX; i++) { |
187 | proposal[i] = buffer_get_cstring(&b,NULL); | 206 | if ((r = sshbuf_get_cstring(b, &(proposal[i]), NULL)) != 0) |
207 | goto out; | ||
188 | debug2("kex_parse_kexinit: %s", proposal[i]); | 208 | debug2("kex_parse_kexinit: %s", proposal[i]); |
189 | } | 209 | } |
190 | /* first kex follows / reserved */ | 210 | /* first kex follows / reserved */ |
191 | i = buffer_get_char(&b); | 211 | if ((r = sshbuf_get_u8(b, &v)) != 0 || |
212 | (r = sshbuf_get_u32(b, &i)) != 0) | ||
213 | goto out; | ||
192 | if (first_kex_follows != NULL) | 214 | if (first_kex_follows != NULL) |
193 | *first_kex_follows = i; | 215 | *first_kex_follows = i; |
194 | debug2("kex_parse_kexinit: first_kex_follows %d ", i); | 216 | debug2("kex_parse_kexinit: first_kex_follows %d ", v); |
195 | i = buffer_get_int(&b); | ||
196 | debug2("kex_parse_kexinit: reserved %u ", i); | 217 | debug2("kex_parse_kexinit: reserved %u ", i); |
197 | buffer_free(&b); | 218 | r = 0; |
198 | return proposal; | 219 | *propp = proposal; |
220 | out: | ||
221 | if (r != 0 && proposal != NULL) | ||
222 | kex_prop_free(proposal); | ||
223 | sshbuf_free(b); | ||
224 | return r; | ||
199 | } | 225 | } |
200 | 226 | ||
201 | static void | 227 | void |
202 | kex_prop_free(char **proposal) | 228 | kex_prop_free(char **proposal) |
203 | { | 229 | { |
204 | u_int i; | 230 | u_int i; |
@@ -217,91 +243,103 @@ kex_protocol_error(int type, u_int32_t seq, void *ctxt) | |||
217 | } | 243 | } |
218 | 244 | ||
219 | static void | 245 | static void |
220 | kex_reset_dispatch(void) | 246 | kex_reset_dispatch(struct ssh *ssh) |
221 | { | 247 | { |
222 | dispatch_range(SSH2_MSG_TRANSPORT_MIN, | 248 | ssh_dispatch_range(ssh, SSH2_MSG_TRANSPORT_MIN, |
223 | SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); | 249 | SSH2_MSG_TRANSPORT_MAX, &kex_protocol_error); |
224 | dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); | 250 | ssh_dispatch_set(ssh, SSH2_MSG_KEXINIT, &kex_input_kexinit); |
225 | } | 251 | } |
226 | 252 | ||
227 | void | 253 | int |
228 | kex_finish(Kex *kex) | 254 | kex_send_newkeys(struct ssh *ssh) |
229 | { | 255 | { |
230 | kex_reset_dispatch(); | 256 | int r; |
231 | 257 | ||
232 | packet_start(SSH2_MSG_NEWKEYS); | 258 | kex_reset_dispatch(ssh); |
233 | packet_send(); | 259 | if ((r = sshpkt_start(ssh, SSH2_MSG_NEWKEYS)) != 0 || |
234 | /* packet_write_wait(); */ | 260 | (r = sshpkt_send(ssh)) != 0) |
261 | return r; | ||
235 | debug("SSH2_MSG_NEWKEYS sent"); | 262 | debug("SSH2_MSG_NEWKEYS sent"); |
236 | |||
237 | debug("expecting SSH2_MSG_NEWKEYS"); | 263 | debug("expecting SSH2_MSG_NEWKEYS"); |
238 | packet_read_expect(SSH2_MSG_NEWKEYS); | 264 | ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_input_newkeys); |
239 | packet_check_eom(); | 265 | return 0; |
240 | debug("SSH2_MSG_NEWKEYS received"); | 266 | } |
267 | |||
268 | static int | ||
269 | kex_input_newkeys(int type, u_int32_t seq, void *ctxt) | ||
270 | { | ||
271 | struct ssh *ssh = ctxt; | ||
272 | struct kex *kex = ssh->kex; | ||
273 | int r; | ||
241 | 274 | ||
275 | debug("SSH2_MSG_NEWKEYS received"); | ||
276 | ssh_dispatch_set(ssh, SSH2_MSG_NEWKEYS, &kex_protocol_error); | ||
277 | if ((r = sshpkt_get_end(ssh)) != 0) | ||
278 | return r; | ||
242 | kex->done = 1; | 279 | kex->done = 1; |
243 | buffer_clear(kex->peer); | 280 | sshbuf_reset(kex->peer); |
244 | /* buffer_clear(kex->my); */ | 281 | /* sshbuf_reset(kex->my); */ |
245 | kex->flags &= ~KEX_INIT_SENT; | 282 | kex->flags &= ~KEX_INIT_SENT; |
246 | free(kex->name); | 283 | free(kex->name); |
247 | kex->name = NULL; | 284 | kex->name = NULL; |
285 | return 0; | ||
248 | } | 286 | } |
249 | 287 | ||
250 | void | 288 | int |
251 | kex_send_kexinit(Kex *kex) | 289 | kex_send_kexinit(struct ssh *ssh) |
252 | { | 290 | { |
253 | u_int32_t rnd = 0; | ||
254 | u_char *cookie; | 291 | u_char *cookie; |
255 | u_int i; | 292 | struct kex *kex = ssh->kex; |
293 | int r; | ||
256 | 294 | ||
257 | if (kex == NULL) { | 295 | if (kex == NULL) |
258 | error("kex_send_kexinit: no kex, cannot rekey"); | 296 | return SSH_ERR_INTERNAL_ERROR; |
259 | return; | 297 | if (kex->flags & KEX_INIT_SENT) |
260 | } | 298 | return 0; |
261 | if (kex->flags & KEX_INIT_SENT) { | ||
262 | debug("KEX_INIT_SENT"); | ||
263 | return; | ||
264 | } | ||
265 | kex->done = 0; | 299 | kex->done = 0; |
266 | 300 | ||
267 | /* generate a random cookie */ | 301 | /* generate a random cookie */ |
268 | if (buffer_len(kex->my) < KEX_COOKIE_LEN) | 302 | if (sshbuf_len(kex->my) < KEX_COOKIE_LEN) |
269 | fatal("kex_send_kexinit: kex proposal too short"); | 303 | return SSH_ERR_INVALID_FORMAT; |
270 | cookie = buffer_ptr(kex->my); | 304 | if ((cookie = sshbuf_mutable_ptr(kex->my)) == NULL) |
271 | for (i = 0; i < KEX_COOKIE_LEN; i++) { | 305 | return SSH_ERR_INTERNAL_ERROR; |
272 | if (i % 4 == 0) | 306 | arc4random_buf(cookie, KEX_COOKIE_LEN); |
273 | rnd = arc4random(); | 307 | |
274 | cookie[i] = rnd; | 308 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEXINIT)) != 0 || |
275 | rnd >>= 8; | 309 | (r = sshpkt_putb(ssh, kex->my)) != 0 || |
276 | } | 310 | (r = sshpkt_send(ssh)) != 0) |
277 | packet_start(SSH2_MSG_KEXINIT); | 311 | return r; |
278 | packet_put_raw(buffer_ptr(kex->my), buffer_len(kex->my)); | ||
279 | packet_send(); | ||
280 | debug("SSH2_MSG_KEXINIT sent"); | 312 | debug("SSH2_MSG_KEXINIT sent"); |
281 | kex->flags |= KEX_INIT_SENT; | 313 | kex->flags |= KEX_INIT_SENT; |
314 | return 0; | ||
282 | } | 315 | } |
283 | 316 | ||
284 | /* ARGSUSED */ | 317 | /* ARGSUSED */ |
285 | int | 318 | int |
286 | kex_input_kexinit(int type, u_int32_t seq, void *ctxt) | 319 | kex_input_kexinit(int type, u_int32_t seq, void *ctxt) |
287 | { | 320 | { |
288 | const char *ptr; | 321 | struct ssh *ssh = ctxt; |
322 | struct kex *kex = ssh->kex; | ||
323 | const u_char *ptr; | ||
289 | u_int i; | 324 | u_int i; |
290 | size_t dlen; | 325 | size_t dlen; |
291 | Kex *kex = (Kex *)ctxt; | 326 | int r; |
292 | 327 | ||
293 | debug("SSH2_MSG_KEXINIT received"); | 328 | debug("SSH2_MSG_KEXINIT received"); |
294 | if (kex == NULL) | 329 | if (kex == NULL) |
295 | fatal("kex_input_kexinit: no kex, cannot rekey"); | 330 | return SSH_ERR_INVALID_ARGUMENT; |
296 | 331 | ||
297 | ptr = packet_get_raw(&dlen); | 332 | ptr = sshpkt_ptr(ssh, &dlen); |
298 | buffer_append(kex->peer, ptr, dlen); | 333 | if ((r = sshbuf_put(kex->peer, ptr, dlen)) != 0) |
334 | return r; | ||
299 | 335 | ||
300 | /* discard packet */ | 336 | /* discard packet */ |
301 | for (i = 0; i < KEX_COOKIE_LEN; i++) | 337 | for (i = 0; i < KEX_COOKIE_LEN; i++) |
302 | packet_get_char(); | 338 | if ((r = sshpkt_get_u8(ssh, NULL)) != 0) |
339 | return r; | ||
303 | for (i = 0; i < PROPOSAL_MAX; i++) | 340 | for (i = 0; i < PROPOSAL_MAX; i++) |
304 | free(packet_get_string(NULL)); | 341 | if ((r = sshpkt_get_string(ssh, NULL, NULL)) != 0) |
342 | return r; | ||
305 | /* | 343 | /* |
306 | * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported | 344 | * XXX RFC4253 sec 7: "each side MAY guess" - currently no supported |
307 | * KEX method has the server move first, but a server might be using | 345 | * KEX method has the server move first, but a server might be using |
@@ -312,12 +350,47 @@ kex_input_kexinit(int type, u_int32_t seq, void *ctxt) | |||
312 | * for cases where the server *doesn't* go first. I guess we should | 350 | * for cases where the server *doesn't* go first. I guess we should |
313 | * ignore it when it is set for these cases, which is what we do now. | 351 | * ignore it when it is set for these cases, which is what we do now. |
314 | */ | 352 | */ |
315 | (void) packet_get_char(); /* first_kex_follows */ | 353 | if ((r = sshpkt_get_u8(ssh, NULL)) != 0 || /* first_kex_follows */ |
316 | (void) packet_get_int(); /* reserved */ | 354 | (r = sshpkt_get_u32(ssh, NULL)) != 0 || /* reserved */ |
317 | packet_check_eom(); | 355 | (r = sshpkt_get_end(ssh)) != 0) |
356 | return r; | ||
318 | 357 | ||
319 | kex_kexinit_finish(kex); | 358 | if (!(kex->flags & KEX_INIT_SENT)) |
320 | return 0; | 359 | if ((r = kex_send_kexinit(ssh)) != 0) |
360 | return r; | ||
361 | if ((r = kex_choose_conf(ssh)) != 0) | ||
362 | return r; | ||
363 | |||
364 | if (kex->kex_type < KEX_MAX && kex->kex[kex->kex_type] != NULL) | ||
365 | return (kex->kex[kex->kex_type])(ssh); | ||
366 | |||
367 | return SSH_ERR_INTERNAL_ERROR; | ||
368 | } | ||
369 | |||
370 | int | ||
371 | kex_new(struct ssh *ssh, char *proposal[PROPOSAL_MAX], struct kex **kexp) | ||
372 | { | ||
373 | struct kex *kex; | ||
374 | int r; | ||
375 | |||
376 | *kexp = NULL; | ||
377 | if ((kex = calloc(1, sizeof(*kex))) == NULL) | ||
378 | return SSH_ERR_ALLOC_FAIL; | ||
379 | if ((kex->peer = sshbuf_new()) == NULL || | ||
380 | (kex->my = sshbuf_new()) == NULL) { | ||
381 | r = SSH_ERR_ALLOC_FAIL; | ||
382 | goto out; | ||
383 | } | ||
384 | if ((r = kex_prop2buf(kex->my, proposal)) != 0) | ||
385 | goto out; | ||
386 | kex->done = 0; | ||
387 | kex_reset_dispatch(ssh); | ||
388 | r = 0; | ||
389 | *kexp = kex; | ||
390 | out: | ||
391 | if (r != 0) | ||
392 | kex_free(kex); | ||
393 | return r; | ||
321 | } | 394 | } |
322 | 395 | ||
323 | void | 396 | void |
@@ -351,51 +424,53 @@ kex_free_newkeys(struct newkeys *newkeys) | |||
351 | free(newkeys); | 424 | free(newkeys); |
352 | } | 425 | } |
353 | 426 | ||
354 | Kex * | 427 | void |
355 | kex_setup(char *proposal[PROPOSAL_MAX]) | 428 | kex_free(struct kex *kex) |
356 | { | 429 | { |
357 | struct kex *kex; | 430 | u_int mode; |
358 | 431 | ||
359 | if ((kex = calloc(1, sizeof(*kex))) == NULL) | 432 | #ifdef WITH_OPENSSL |
360 | fatal("%s: calloc", __func__); | 433 | if (kex->dh) |
361 | if ((kex->peer = sshbuf_new()) == NULL || | 434 | DH_free(kex->dh); |
362 | (kex->my = sshbuf_new()) == NULL) { | 435 | if (kex->ec_client_key) |
363 | fatal("%s: sshbuf_new", __func__); | 436 | EC_KEY_free(kex->ec_client_key); |
437 | #endif | ||
438 | for (mode = 0; mode < MODE_MAX; mode++) { | ||
439 | kex_free_newkeys(kex->newkeys[mode]); | ||
440 | kex->newkeys[mode] = NULL; | ||
364 | } | 441 | } |
365 | kex_prop2buf(kex->my, proposal); | 442 | sshbuf_free(kex->peer); |
366 | kex->done = 0; | 443 | sshbuf_free(kex->my); |
367 | 444 | free(kex->session_id); | |
368 | kex_send_kexinit(kex); /* we start */ | 445 | free(kex->client_version_string); |
369 | kex_reset_dispatch(); | 446 | free(kex->server_version_string); |
370 | 447 | free(kex); | |
371 | return kex; | ||
372 | } | 448 | } |
373 | 449 | ||
374 | static void | 450 | int |
375 | kex_kexinit_finish(Kex *kex) | 451 | kex_setup(struct ssh *ssh, char *proposal[PROPOSAL_MAX]) |
376 | { | 452 | { |
377 | if (!(kex->flags & KEX_INIT_SENT)) | 453 | int r; |
378 | kex_send_kexinit(kex); | 454 | |
379 | 455 | if ((r = kex_new(ssh, proposal, &ssh->kex)) != 0) | |
380 | kex_choose_conf(kex); | 456 | return r; |
381 | 457 | if ((r = kex_send_kexinit(ssh)) != 0) { /* we start */ | |
382 | if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX && | 458 | kex_free(ssh->kex); |
383 | kex->kex[kex->kex_type] != NULL) { | 459 | ssh->kex = NULL; |
384 | (kex->kex[kex->kex_type])(kex); | 460 | return r; |
385 | } else { | ||
386 | fatal("Unsupported key exchange %d", kex->kex_type); | ||
387 | } | 461 | } |
462 | return 0; | ||
388 | } | 463 | } |
389 | 464 | ||
390 | static void | 465 | static int |
391 | choose_enc(Enc *enc, char *client, char *server) | 466 | choose_enc(struct sshenc *enc, char *client, char *server) |
392 | { | 467 | { |
393 | char *name = match_list(client, server, NULL); | 468 | char *name = match_list(client, server, NULL); |
469 | |||
394 | if (name == NULL) | 470 | if (name == NULL) |
395 | fatal("no matching cipher found: client %s server %s", | 471 | return SSH_ERR_NO_CIPHER_ALG_MATCH; |
396 | client, server); | ||
397 | if ((enc->cipher = cipher_by_name(name)) == NULL) | 472 | if ((enc->cipher = cipher_by_name(name)) == NULL) |
398 | fatal("matching cipher is not supported: %s", name); | 473 | return SSH_ERR_INTERNAL_ERROR; |
399 | enc->name = name; | 474 | enc->name = name; |
400 | enc->enabled = 0; | 475 | enc->enabled = 0; |
401 | enc->iv = NULL; | 476 | enc->iv = NULL; |
@@ -403,31 +478,34 @@ choose_enc(Enc *enc, char *client, char *server) | |||
403 | enc->key = NULL; | 478 | enc->key = NULL; |
404 | enc->key_len = cipher_keylen(enc->cipher); | 479 | enc->key_len = cipher_keylen(enc->cipher); |
405 | enc->block_size = cipher_blocksize(enc->cipher); | 480 | enc->block_size = cipher_blocksize(enc->cipher); |
481 | return 0; | ||
406 | } | 482 | } |
407 | 483 | ||
408 | static void | 484 | static int |
409 | choose_mac(Mac *mac, char *client, char *server) | 485 | choose_mac(struct ssh *ssh, struct sshmac *mac, char *client, char *server) |
410 | { | 486 | { |
411 | char *name = match_list(client, server, NULL); | 487 | char *name = match_list(client, server, NULL); |
488 | |||
412 | if (name == NULL) | 489 | if (name == NULL) |
413 | fatal("no matching mac found: client %s server %s", | 490 | return SSH_ERR_NO_MAC_ALG_MATCH; |
414 | client, server); | ||
415 | if (mac_setup(mac, name) < 0) | 491 | if (mac_setup(mac, name) < 0) |
416 | fatal("unsupported mac %s", name); | 492 | return SSH_ERR_INTERNAL_ERROR; |
417 | /* truncate the key */ | 493 | /* truncate the key */ |
418 | if (datafellows & SSH_BUG_HMAC) | 494 | if (ssh->compat & SSH_BUG_HMAC) |
419 | mac->key_len = 16; | 495 | mac->key_len = 16; |
420 | mac->name = name; | 496 | mac->name = name; |
421 | mac->key = NULL; | 497 | mac->key = NULL; |
422 | mac->enabled = 0; | 498 | mac->enabled = 0; |
499 | return 0; | ||
423 | } | 500 | } |
424 | 501 | ||
425 | static void | 502 | static int |
426 | choose_comp(Comp *comp, char *client, char *server) | 503 | choose_comp(struct sshcomp *comp, char *client, char *server) |
427 | { | 504 | { |
428 | char *name = match_list(client, server, NULL); | 505 | char *name = match_list(client, server, NULL); |
506 | |||
429 | if (name == NULL) | 507 | if (name == NULL) |
430 | fatal("no matching comp found: client %s server %s", client, server); | 508 | return SSH_ERR_NO_COMPRESS_ALG_MATCH; |
431 | if (strcmp(name, "zlib@openssh.com") == 0) { | 509 | if (strcmp(name, "zlib@openssh.com") == 0) { |
432 | comp->type = COMP_DELAYED; | 510 | comp->type = COMP_DELAYED; |
433 | } else if (strcmp(name, "zlib") == 0) { | 511 | } else if (strcmp(name, "zlib") == 0) { |
@@ -435,36 +513,41 @@ choose_comp(Comp *comp, char *client, char *server) | |||
435 | } else if (strcmp(name, "none") == 0) { | 513 | } else if (strcmp(name, "none") == 0) { |
436 | comp->type = COMP_NONE; | 514 | comp->type = COMP_NONE; |
437 | } else { | 515 | } else { |
438 | fatal("unsupported comp %s", name); | 516 | return SSH_ERR_INTERNAL_ERROR; |
439 | } | 517 | } |
440 | comp->name = name; | 518 | comp->name = name; |
519 | return 0; | ||
441 | } | 520 | } |
442 | 521 | ||
443 | static void | 522 | static int |
444 | choose_kex(Kex *k, char *client, char *server) | 523 | choose_kex(struct kex *k, char *client, char *server) |
445 | { | 524 | { |
446 | const struct kexalg *kexalg; | 525 | const struct kexalg *kexalg; |
447 | 526 | ||
448 | k->name = match_list(client, server, NULL); | 527 | k->name = match_list(client, server, NULL); |
528 | |||
449 | if (k->name == NULL) | 529 | if (k->name == NULL) |
450 | fatal("Unable to negotiate a key exchange method"); | 530 | return SSH_ERR_NO_KEX_ALG_MATCH; |
451 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) | 531 | if ((kexalg = kex_alg_by_name(k->name)) == NULL) |
452 | fatal("unsupported kex alg %s", k->name); | 532 | return SSH_ERR_INTERNAL_ERROR; |
453 | k->kex_type = kexalg->type; | 533 | k->kex_type = kexalg->type; |
454 | k->hash_alg = kexalg->hash_alg; | 534 | k->hash_alg = kexalg->hash_alg; |
455 | k->ec_nid = kexalg->ec_nid; | 535 | k->ec_nid = kexalg->ec_nid; |
536 | return 0; | ||
456 | } | 537 | } |
457 | 538 | ||
458 | static void | 539 | static int |
459 | choose_hostkeyalg(Kex *k, char *client, char *server) | 540 | choose_hostkeyalg(struct kex *k, char *client, char *server) |
460 | { | 541 | { |
461 | char *hostkeyalg = match_list(client, server, NULL); | 542 | char *hostkeyalg = match_list(client, server, NULL); |
543 | |||
462 | if (hostkeyalg == NULL) | 544 | if (hostkeyalg == NULL) |
463 | fatal("no hostkey alg"); | 545 | return SSH_ERR_NO_HOSTKEY_ALG_MATCH; |
464 | k->hostkey_type = key_type_from_name(hostkeyalg); | 546 | k->hostkey_type = sshkey_type_from_name(hostkeyalg); |
465 | if (k->hostkey_type == KEY_UNSPEC) | 547 | if (k->hostkey_type == KEY_UNSPEC) |
466 | fatal("bad hostkey alg '%s'", hostkeyalg); | 548 | return SSH_ERR_INTERNAL_ERROR; |
467 | free(hostkeyalg); | 549 | free(hostkeyalg); |
550 | return 0; | ||
468 | } | 551 | } |
469 | 552 | ||
470 | static int | 553 | static int |
@@ -491,18 +574,20 @@ proposals_match(char *my[PROPOSAL_MAX], char *peer[PROPOSAL_MAX]) | |||
491 | return (1); | 574 | return (1); |
492 | } | 575 | } |
493 | 576 | ||
494 | static void | 577 | static int |
495 | kex_choose_conf(Kex *kex) | 578 | kex_choose_conf(struct ssh *ssh) |
496 | { | 579 | { |
497 | Newkeys *newkeys; | 580 | struct kex *kex = ssh->kex; |
498 | char **my, **peer; | 581 | struct newkeys *newkeys; |
582 | char **my = NULL, **peer = NULL; | ||
499 | char **cprop, **sprop; | 583 | char **cprop, **sprop; |
500 | int nenc, nmac, ncomp; | 584 | int nenc, nmac, ncomp; |
501 | u_int mode, ctos, need, dh_need, authlen; | 585 | u_int mode, ctos, need, dh_need, authlen; |
502 | int first_kex_follows, type; | 586 | int r, first_kex_follows; |
503 | 587 | ||
504 | my = kex_buf2prop(kex->my, NULL); | 588 | if ((r = kex_buf2prop(kex->my, NULL, &my)) != 0 || |
505 | peer = kex_buf2prop(kex->peer, &first_kex_follows); | 589 | (r = kex_buf2prop(kex->peer, &first_kex_follows, &peer)) != 0) |
590 | goto out; | ||
506 | 591 | ||
507 | if (kex->server) { | 592 | if (kex->server) { |
508 | cprop=peer; | 593 | cprop=peer; |
@@ -514,8 +599,9 @@ kex_choose_conf(Kex *kex) | |||
514 | 599 | ||
515 | /* Check whether server offers roaming */ | 600 | /* Check whether server offers roaming */ |
516 | if (!kex->server) { | 601 | if (!kex->server) { |
517 | char *roaming; | 602 | char *roaming = match_list(KEX_RESUME, |
518 | roaming = match_list(KEX_RESUME, peer[PROPOSAL_KEX_ALGS], NULL); | 603 | peer[PROPOSAL_KEX_ALGS], NULL); |
604 | |||
519 | if (roaming) { | 605 | if (roaming) { |
520 | kex->roaming = 1; | 606 | kex->roaming = 1; |
521 | free(roaming); | 607 | free(roaming); |
@@ -524,28 +610,39 @@ kex_choose_conf(Kex *kex) | |||
524 | 610 | ||
525 | /* Algorithm Negotiation */ | 611 | /* Algorithm Negotiation */ |
526 | for (mode = 0; mode < MODE_MAX; mode++) { | 612 | for (mode = 0; mode < MODE_MAX; mode++) { |
527 | newkeys = xcalloc(1, sizeof(*newkeys)); | 613 | if ((newkeys = calloc(1, sizeof(*newkeys))) == NULL) { |
614 | r = SSH_ERR_ALLOC_FAIL; | ||
615 | goto out; | ||
616 | } | ||
528 | kex->newkeys[mode] = newkeys; | 617 | kex->newkeys[mode] = newkeys; |
529 | ctos = (!kex->server && mode == MODE_OUT) || | 618 | ctos = (!kex->server && mode == MODE_OUT) || |
530 | (kex->server && mode == MODE_IN); | 619 | (kex->server && mode == MODE_IN); |
531 | nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; | 620 | nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC; |
532 | nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; | 621 | nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC; |
533 | ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; | 622 | ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC; |
534 | choose_enc(&newkeys->enc, cprop[nenc], sprop[nenc]); | 623 | if ((r = choose_enc(&newkeys->enc, cprop[nenc], |
535 | /* ignore mac for authenticated encryption */ | 624 | sprop[nenc])) != 0) |
625 | goto out; | ||
536 | authlen = cipher_authlen(newkeys->enc.cipher); | 626 | authlen = cipher_authlen(newkeys->enc.cipher); |
537 | if (authlen == 0) | 627 | /* ignore mac for authenticated encryption */ |
538 | choose_mac(&newkeys->mac, cprop[nmac], sprop[nmac]); | 628 | if (authlen == 0 && |
539 | choose_comp(&newkeys->comp, cprop[ncomp], sprop[ncomp]); | 629 | (r = choose_mac(ssh, &newkeys->mac, cprop[nmac], |
630 | sprop[nmac])) != 0) | ||
631 | goto out; | ||
632 | if ((r = choose_comp(&newkeys->comp, cprop[ncomp], | ||
633 | sprop[ncomp])) != 0) | ||
634 | goto out; | ||
540 | debug("kex: %s %s %s %s", | 635 | debug("kex: %s %s %s %s", |
541 | ctos ? "client->server" : "server->client", | 636 | ctos ? "client->server" : "server->client", |
542 | newkeys->enc.name, | 637 | newkeys->enc.name, |
543 | authlen == 0 ? newkeys->mac.name : "<implicit>", | 638 | authlen == 0 ? newkeys->mac.name : "<implicit>", |
544 | newkeys->comp.name); | 639 | newkeys->comp.name); |
545 | } | 640 | } |
546 | choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]); | 641 | if ((r = choose_kex(kex, cprop[PROPOSAL_KEX_ALGS], |
547 | choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], | 642 | sprop[PROPOSAL_KEX_ALGS])) != 0 || |
548 | sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]); | 643 | (r = choose_hostkeyalg(kex, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS], |
644 | sprop[PROPOSAL_SERVER_HOST_KEY_ALGS])) != 0) | ||
645 | goto out; | ||
549 | need = dh_need = 0; | 646 | need = dh_need = 0; |
550 | for (mode = 0; mode < MODE_MAX; mode++) { | 647 | for (mode = 0; mode < MODE_MAX; mode++) { |
551 | newkeys = kex->newkeys[mode]; | 648 | newkeys = kex->newkeys[mode]; |
@@ -564,45 +661,47 @@ kex_choose_conf(Kex *kex) | |||
564 | 661 | ||
565 | /* ignore the next message if the proposals do not match */ | 662 | /* ignore the next message if the proposals do not match */ |
566 | if (first_kex_follows && !proposals_match(my, peer) && | 663 | if (first_kex_follows && !proposals_match(my, peer) && |
567 | !(datafellows & SSH_BUG_FIRSTKEX)) { | 664 | !(ssh->compat & SSH_BUG_FIRSTKEX)) |
568 | type = packet_read(); | 665 | ssh->dispatch_skip_packets = 1; |
569 | debug2("skipping next packet (type %u)", type); | 666 | r = 0; |
570 | } | 667 | out: |
571 | |||
572 | kex_prop_free(my); | 668 | kex_prop_free(my); |
573 | kex_prop_free(peer); | 669 | kex_prop_free(peer); |
670 | return r; | ||
574 | } | 671 | } |
575 | 672 | ||
576 | static u_char * | 673 | static int |
577 | derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, | 674 | derive_key(struct ssh *ssh, int id, u_int need, u_char *hash, u_int hashlen, |
578 | const u_char *shared_secret, u_int slen) | 675 | const struct sshbuf *shared_secret, u_char **keyp) |
579 | { | 676 | { |
580 | Buffer b; | 677 | struct kex *kex = ssh->kex; |
581 | struct ssh_digest_ctx *hashctx; | 678 | struct ssh_digest_ctx *hashctx = NULL; |
582 | char c = id; | 679 | char c = id; |
583 | u_int have; | 680 | u_int have; |
584 | size_t mdsz; | 681 | size_t mdsz; |
585 | u_char *digest; | 682 | u_char *digest; |
683 | int r; | ||
586 | 684 | ||
587 | if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) | 685 | if ((mdsz = ssh_digest_bytes(kex->hash_alg)) == 0) |
588 | fatal("bad kex md size %zu", mdsz); | 686 | return SSH_ERR_INVALID_ARGUMENT; |
589 | digest = xmalloc(roundup(need, mdsz)); | 687 | if ((digest = calloc(1, roundup(need, mdsz))) == NULL) { |
590 | 688 | r = SSH_ERR_ALLOC_FAIL; | |
591 | buffer_init(&b); | 689 | goto out; |
592 | buffer_append(&b, shared_secret, slen); | 690 | } |
593 | 691 | ||
594 | /* K1 = HASH(K || H || "A" || session_id) */ | 692 | /* K1 = HASH(K || H || "A" || session_id) */ |
595 | if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) | 693 | if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || |
596 | fatal("%s: ssh_digest_start failed", __func__); | 694 | ssh_digest_update_buffer(hashctx, shared_secret) != 0 || |
597 | if (ssh_digest_update_buffer(hashctx, &b) != 0 || | ||
598 | ssh_digest_update(hashctx, hash, hashlen) != 0 || | 695 | ssh_digest_update(hashctx, hash, hashlen) != 0 || |
599 | ssh_digest_update(hashctx, &c, 1) != 0 || | 696 | ssh_digest_update(hashctx, &c, 1) != 0 || |
600 | ssh_digest_update(hashctx, kex->session_id, | 697 | ssh_digest_update(hashctx, kex->session_id, |
601 | kex->session_id_len) != 0) | 698 | kex->session_id_len) != 0 || |
602 | fatal("%s: ssh_digest_update failed", __func__); | 699 | ssh_digest_final(hashctx, digest, mdsz) != 0) { |
603 | if (ssh_digest_final(hashctx, digest, mdsz) != 0) | 700 | r = SSH_ERR_LIBCRYPTO_ERROR; |
604 | fatal("%s: ssh_digest_final failed", __func__); | 701 | goto out; |
702 | } | ||
605 | ssh_digest_free(hashctx); | 703 | ssh_digest_free(hashctx); |
704 | hashctx = NULL; | ||
606 | 705 | ||
607 | /* | 706 | /* |
608 | * expand key: | 707 | * expand key: |
@@ -610,38 +709,49 @@ derive_key(Kex *kex, int id, u_int need, u_char *hash, u_int hashlen, | |||
610 | * Key = K1 || K2 || ... || Kn | 709 | * Key = K1 || K2 || ... || Kn |
611 | */ | 710 | */ |
612 | for (have = mdsz; need > have; have += mdsz) { | 711 | for (have = mdsz; need > have; have += mdsz) { |
613 | if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL) | 712 | if ((hashctx = ssh_digest_start(kex->hash_alg)) == NULL || |
614 | fatal("%s: ssh_digest_start failed", __func__); | 713 | ssh_digest_update_buffer(hashctx, shared_secret) != 0 || |
615 | if (ssh_digest_update_buffer(hashctx, &b) != 0 || | ||
616 | ssh_digest_update(hashctx, hash, hashlen) != 0 || | 714 | ssh_digest_update(hashctx, hash, hashlen) != 0 || |
617 | ssh_digest_update(hashctx, digest, have) != 0) | 715 | ssh_digest_update(hashctx, digest, have) != 0 || |
618 | fatal("%s: ssh_digest_update failed", __func__); | 716 | ssh_digest_final(hashctx, digest + have, mdsz) != 0) { |
619 | if (ssh_digest_final(hashctx, digest + have, mdsz) != 0) | 717 | r = SSH_ERR_LIBCRYPTO_ERROR; |
620 | fatal("%s: ssh_digest_final failed", __func__); | 718 | goto out; |
719 | } | ||
621 | ssh_digest_free(hashctx); | 720 | ssh_digest_free(hashctx); |
721 | hashctx = NULL; | ||
622 | } | 722 | } |
623 | buffer_free(&b); | ||
624 | #ifdef DEBUG_KEX | 723 | #ifdef DEBUG_KEX |
625 | fprintf(stderr, "key '%c'== ", c); | 724 | fprintf(stderr, "key '%c'== ", c); |
626 | dump_digest("key", digest, need); | 725 | dump_digest("key", digest, need); |
627 | #endif | 726 | #endif |
628 | return digest; | 727 | *keyp = digest; |
728 | digest = NULL; | ||
729 | r = 0; | ||
730 | out: | ||
731 | if (digest) | ||
732 | free(digest); | ||
733 | ssh_digest_free(hashctx); | ||
734 | return r; | ||
629 | } | 735 | } |
630 | 736 | ||
631 | #define NKEYS 6 | 737 | #define NKEYS 6 |
632 | void | 738 | int |
633 | kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, | 739 | kex_derive_keys(struct ssh *ssh, u_char *hash, u_int hashlen, |
634 | const u_char *shared_secret, u_int slen) | 740 | const struct sshbuf *shared_secret) |
635 | { | 741 | { |
742 | struct kex *kex = ssh->kex; | ||
636 | u_char *keys[NKEYS]; | 743 | u_char *keys[NKEYS]; |
637 | u_int i, mode, ctos; | 744 | u_int i, j, mode, ctos; |
745 | int r; | ||
638 | 746 | ||
639 | for (i = 0; i < NKEYS; i++) { | 747 | for (i = 0; i < NKEYS; i++) { |
640 | keys[i] = derive_key(kex, 'A'+i, kex->we_need, hash, hashlen, | 748 | if ((r = derive_key(ssh, 'A'+i, kex->we_need, hash, hashlen, |
641 | shared_secret, slen); | 749 | shared_secret, &keys[i])) != 0) { |
750 | for (j = 0; j < i; j++) | ||
751 | free(keys[j]); | ||
752 | return r; | ||
753 | } | ||
642 | } | 754 | } |
643 | |||
644 | debug2("kex_derive_keys"); | ||
645 | for (mode = 0; mode < MODE_MAX; mode++) { | 755 | for (mode = 0; mode < MODE_MAX; mode++) { |
646 | ctos = (!kex->server && mode == MODE_OUT) || | 756 | ctos = (!kex->server && mode == MODE_OUT) || |
647 | (kex->server && mode == MODE_IN); | 757 | (kex->server && mode == MODE_IN); |
@@ -649,54 +759,54 @@ kex_derive_keys(Kex *kex, u_char *hash, u_int hashlen, | |||
649 | kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; | 759 | kex->newkeys[mode]->enc.key = keys[ctos ? 2 : 3]; |
650 | kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; | 760 | kex->newkeys[mode]->mac.key = keys[ctos ? 4 : 5]; |
651 | } | 761 | } |
762 | return 0; | ||
652 | } | 763 | } |
653 | 764 | ||
654 | #ifdef WITH_OPENSSL | 765 | #ifdef WITH_OPENSSL |
655 | void | 766 | int |
656 | kex_derive_keys_bn(Kex *kex, u_char *hash, u_int hashlen, const BIGNUM *secret) | 767 | kex_derive_keys_bn(struct ssh *ssh, u_char *hash, u_int hashlen, |
768 | const BIGNUM *secret) | ||
657 | { | 769 | { |
658 | Buffer shared_secret; | 770 | struct sshbuf *shared_secret; |
659 | 771 | int r; | |
660 | buffer_init(&shared_secret); | 772 | |
661 | buffer_put_bignum2(&shared_secret, secret); | 773 | if ((shared_secret = sshbuf_new()) == NULL) |
662 | kex_derive_keys(kex, hash, hashlen, | 774 | return SSH_ERR_ALLOC_FAIL; |
663 | buffer_ptr(&shared_secret), buffer_len(&shared_secret)); | 775 | if ((r = sshbuf_put_bignum2(shared_secret, secret)) == 0) |
664 | buffer_free(&shared_secret); | 776 | r = kex_derive_keys(ssh, hash, hashlen, shared_secret); |
777 | sshbuf_free(shared_secret); | ||
778 | return r; | ||
665 | } | 779 | } |
666 | #endif | 780 | #endif |
667 | 781 | ||
668 | #ifdef WITH_SSH1 | 782 | #ifdef WITH_SSH1 |
669 | void | 783 | int |
670 | derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, | 784 | derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, |
671 | u_int8_t cookie[8], u_int8_t id[16]) | 785 | u_int8_t cookie[8], u_int8_t id[16]) |
672 | { | 786 | { |
673 | u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; | 787 | u_int8_t nbuf[2048], obuf[SSH_DIGEST_MAX_LENGTH]; |
674 | int len; | 788 | struct ssh_digest_ctx *hashctx = NULL; |
675 | struct ssh_digest_ctx *hashctx; | 789 | size_t len; |
676 | 790 | int r; | |
677 | if ((hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL) | ||
678 | fatal("%s: ssh_digest_start", __func__); | ||
679 | 791 | ||
680 | len = BN_num_bytes(host_modulus); | 792 | len = BN_num_bytes(host_modulus); |
681 | if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) | 793 | if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) |
682 | fatal("%s: bad host modulus (len %d)", __func__, len); | 794 | return SSH_ERR_KEY_BITS_MISMATCH; |
683 | BN_bn2bin(host_modulus, nbuf); | 795 | if (BN_bn2bin(host_modulus, nbuf) <= 0 || |
684 | if (ssh_digest_update(hashctx, nbuf, len) != 0) | 796 | (hashctx = ssh_digest_start(SSH_DIGEST_MD5)) == NULL || |
685 | fatal("%s: ssh_digest_update failed", __func__); | 797 | ssh_digest_update(hashctx, nbuf, len) != 0 || |
686 | 798 | ssh_digest_update(hashctx, cookie, 8) != 0 || | |
687 | len = BN_num_bytes(server_modulus); | 799 | ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) { |
688 | if (len < (512 / 8) || (u_int)len > sizeof(nbuf)) | 800 | r = SSH_ERR_LIBCRYPTO_ERROR; |
689 | fatal("%s: bad server modulus (len %d)", __func__, len); | 801 | goto out; |
690 | BN_bn2bin(server_modulus, nbuf); | 802 | } |
691 | if (ssh_digest_update(hashctx, nbuf, len) != 0 || | ||
692 | ssh_digest_update(hashctx, cookie, 8) != 0) | ||
693 | fatal("%s: ssh_digest_update failed", __func__); | ||
694 | if (ssh_digest_final(hashctx, obuf, sizeof(obuf)) != 0) | ||
695 | fatal("%s: ssh_digest_final failed", __func__); | ||
696 | memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); | 803 | memcpy(id, obuf, ssh_digest_bytes(SSH_DIGEST_MD5)); |
697 | 804 | r = 0; | |
805 | out: | ||
806 | ssh_digest_free(hashctx); | ||
698 | explicit_bzero(nbuf, sizeof(nbuf)); | 807 | explicit_bzero(nbuf, sizeof(nbuf)); |
699 | explicit_bzero(obuf, sizeof(obuf)); | 808 | explicit_bzero(obuf, sizeof(obuf)); |
809 | return r; | ||
700 | } | 810 | } |
701 | #endif | 811 | #endif |
702 | 812 | ||
@@ -704,16 +814,7 @@ derive_ssh1_session_id(BIGNUM *host_modulus, BIGNUM *server_modulus, | |||
704 | void | 814 | void |
705 | dump_digest(char *msg, u_char *digest, int len) | 815 | dump_digest(char *msg, u_char *digest, int len) |
706 | { | 816 | { |
707 | int i; | ||
708 | |||
709 | fprintf(stderr, "%s\n", msg); | 817 | fprintf(stderr, "%s\n", msg); |
710 | for (i = 0; i < len; i++) { | 818 | sshbuf_dump_data(digest, len, stderr); |
711 | fprintf(stderr, "%02x", digest[i]); | ||
712 | if (i%32 == 31) | ||
713 | fprintf(stderr, "\n"); | ||
714 | else if (i%8 == 7) | ||
715 | fprintf(stderr, " "); | ||
716 | } | ||
717 | fprintf(stderr, "\n"); | ||
718 | } | 819 | } |
719 | #endif | 820 | #endif |