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