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