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 | |
parent | 3fdc88a0def4f86aa88a5846ac079dc964c0546a (diff) |
upstream commit
adapt kex to sshbuf and struct ssh; ok djm@
-rw-r--r-- | auth.h | 13 | ||||
-rw-r--r-- | clientloop.c | 11 | ||||
-rw-r--r-- | dh.c | 59 | ||||
-rw-r--r-- | dh.h | 6 | ||||
-rw-r--r-- | kex.c | 575 | ||||
-rw-r--r-- | kex.h | 127 | ||||
-rw-r--r-- | kexc25519.c | 94 | ||||
-rw-r--r-- | kexc25519c.c | 159 | ||||
-rw-r--r-- | kexc25519s.c | 133 | ||||
-rw-r--r-- | kexdh.c | 87 | ||||
-rw-r--r-- | kexdhc.c | 194 | ||||
-rw-r--r-- | kexdhs.c | 186 | ||||
-rw-r--r-- | kexecdh.c | 81 | ||||
-rw-r--r-- | kexecdhc.c | 207 | ||||
-rw-r--r-- | kexecdhs.c | 190 | ||||
-rw-r--r-- | kexgex.c | 105 | ||||
-rw-r--r-- | kexgexc.c | 287 | ||||
-rw-r--r-- | kexgexs.c | 257 | ||||
-rw-r--r-- | monitor.c | 4 | ||||
-rw-r--r-- | monitor_wrap.c | 6 | ||||
-rw-r--r-- | serverloop.c | 6 | ||||
-rw-r--r-- | ssh-keyscan.c | 14 | ||||
-rw-r--r-- | sshconnect2.c | 12 | ||||
-rw-r--r-- | sshd.c | 47 |
24 files changed, 1704 insertions, 1156 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: auth.h,v 1.79 2014/12/22 07:51:30 djm Exp $ */ | 1 | /* $OpenBSD: auth.h,v 1.80 2015/01/19 20:16:15 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -42,6 +42,7 @@ | |||
42 | #include <krb5.h> | 42 | #include <krb5.h> |
43 | #endif | 43 | #endif |
44 | 44 | ||
45 | struct ssh; | ||
45 | struct sshkey; | 46 | struct sshkey; |
46 | 47 | ||
47 | typedef struct Authctxt Authctxt; | 48 | typedef struct Authctxt Authctxt; |
@@ -202,12 +203,12 @@ check_key_in_hostfiles(struct passwd *, Key *, const char *, | |||
202 | 203 | ||
203 | /* hostkey handling */ | 204 | /* hostkey handling */ |
204 | Key *get_hostkey_by_index(int); | 205 | Key *get_hostkey_by_index(int); |
205 | Key *get_hostkey_public_by_index(int); | 206 | Key *get_hostkey_public_by_index(int, struct ssh *); |
206 | Key *get_hostkey_public_by_type(int); | 207 | Key *get_hostkey_public_by_type(int, struct ssh *); |
207 | Key *get_hostkey_private_by_type(int); | 208 | Key *get_hostkey_private_by_type(int, struct ssh *); |
208 | int get_hostkey_index(Key *); | 209 | int get_hostkey_index(Key *, struct ssh *); |
209 | int ssh1_session_key(BIGNUM *); | 210 | int ssh1_session_key(BIGNUM *); |
210 | void sshd_hostkey_sign(Key *, Key *, u_char **, u_int *, u_char *, u_int); | 211 | int sshd_hostkey_sign(Key *, Key *, u_char **, size_t *, u_char *, size_t, u_int); |
211 | 212 | ||
212 | /* debug messages during authentication */ | 213 | /* debug messages during authentication */ |
213 | void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); | 214 | void auth_debug_add(const char *fmt,...) __attribute__((format(printf, 1, 2))); |
diff --git a/clientloop.c b/clientloop.c index 672d06989..5a018ac79 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.264 2015/01/19 20:07:45 markus Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.265 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -1413,8 +1413,7 @@ client_process_output(fd_set *writeset) | |||
1413 | static void | 1413 | static void |
1414 | client_process_buffered_input_packets(void) | 1414 | client_process_buffered_input_packets(void) |
1415 | { | 1415 | { |
1416 | dispatch_run(DISPATCH_NONBLOCK, &quit_pending, | 1416 | dispatch_run(DISPATCH_NONBLOCK, &quit_pending, active_state); |
1417 | compat20 ? active_state->kex : NULL); | ||
1418 | } | 1417 | } |
1419 | 1418 | ||
1420 | /* scan buf[] for '~' before sending data to the peer */ | 1419 | /* scan buf[] for '~' before sending data to the peer */ |
@@ -1468,7 +1467,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1468 | { | 1467 | { |
1469 | fd_set *readset = NULL, *writeset = NULL; | 1468 | fd_set *readset = NULL, *writeset = NULL; |
1470 | double start_time, total_time; | 1469 | double start_time, total_time; |
1471 | int max_fd = 0, max_fd2 = 0, len, rekeying = 0; | 1470 | int r, max_fd = 0, max_fd2 = 0, len, rekeying = 0; |
1472 | u_int64_t ibytes, obytes; | 1471 | u_int64_t ibytes, obytes; |
1473 | u_int nalloc = 0; | 1472 | u_int nalloc = 0; |
1474 | char buf[100]; | 1473 | char buf[100]; |
@@ -1598,7 +1597,9 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1598 | if (need_rekeying || packet_need_rekeying()) { | 1597 | if (need_rekeying || packet_need_rekeying()) { |
1599 | debug("need rekeying"); | 1598 | debug("need rekeying"); |
1600 | active_state->kex->done = 0; | 1599 | active_state->kex->done = 0; |
1601 | kex_send_kexinit(active_state->kex); | 1600 | if ((r = kex_send_kexinit(active_state)) != 0) |
1601 | fatal("%s: kex_send_kexinit: %s", | ||
1602 | __func__, ssh_err(r)); | ||
1602 | need_rekeying = 0; | 1603 | need_rekeying = 0; |
1603 | } | 1604 | } |
1604 | } | 1605 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dh.c,v 1.53 2013/11/21 00:45:44 djm Exp $ */ | 1 | /* $OpenBSD: dh.c,v 1.54 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Niels Provos. All rights reserved. | 3 | * Copyright (c) 2000 Niels Provos. All rights reserved. |
4 | * | 4 | * |
@@ -39,6 +39,7 @@ | |||
39 | #include "pathnames.h" | 39 | #include "pathnames.h" |
40 | #include "log.h" | 40 | #include "log.h" |
41 | #include "misc.h" | 41 | #include "misc.h" |
42 | #include "ssherr.h" | ||
42 | 43 | ||
43 | static int | 44 | static int |
44 | parse_prime(int linenum, char *line, struct dhgroup *dhg) | 45 | parse_prime(int linenum, char *line, struct dhgroup *dhg) |
@@ -107,10 +108,11 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg) | |||
107 | goto fail; | 108 | goto fail; |
108 | } | 109 | } |
109 | 110 | ||
110 | if ((dhg->g = BN_new()) == NULL) | 111 | if ((dhg->g = BN_new()) == NULL || |
111 | fatal("parse_prime: BN_new failed"); | 112 | (dhg->p = BN_new()) == NULL) { |
112 | if ((dhg->p = BN_new()) == NULL) | 113 | error("parse_prime: BN_new failed"); |
113 | fatal("parse_prime: BN_new failed"); | 114 | goto fail; |
115 | } | ||
114 | if (BN_hex2bn(&dhg->g, gen) == 0) { | 116 | if (BN_hex2bn(&dhg->g, gen) == 0) { |
115 | error("moduli:%d: could not parse generator value", linenum); | 117 | error("moduli:%d: could not parse generator value", linenum); |
116 | goto fail; | 118 | goto fail; |
@@ -128,7 +130,6 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg) | |||
128 | error("moduli:%d: generator is invalid", linenum); | 130 | error("moduli:%d: generator is invalid", linenum); |
129 | goto fail; | 131 | goto fail; |
130 | } | 132 | } |
131 | |||
132 | return 1; | 133 | return 1; |
133 | 134 | ||
134 | fail: | 135 | fail: |
@@ -137,7 +138,6 @@ parse_prime(int linenum, char *line, struct dhgroup *dhg) | |||
137 | if (dhg->p != NULL) | 138 | if (dhg->p != NULL) |
138 | BN_clear_free(dhg->p); | 139 | BN_clear_free(dhg->p); |
139 | dhg->g = dhg->p = NULL; | 140 | dhg->g = dhg->p = NULL; |
140 | error("Bad prime description in line %d", linenum); | ||
141 | return 0; | 141 | return 0; |
142 | } | 142 | } |
143 | 143 | ||
@@ -200,9 +200,11 @@ choose_dh(int min, int wantbits, int max) | |||
200 | break; | 200 | break; |
201 | } | 201 | } |
202 | fclose(f); | 202 | fclose(f); |
203 | if (linenum != which+1) | 203 | if (linenum != which+1) { |
204 | fatal("WARNING: line %d disappeared in %s, giving up", | 204 | logit("WARNING: line %d disappeared in %s, giving up", |
205 | which, _PATH_DH_PRIMES); | 205 | which, _PATH_DH_PRIMES); |
206 | return (dh_new_group14()); | ||
207 | } | ||
206 | 208 | ||
207 | return (dh_new_group(dhg.g, dhg.p)); | 209 | return (dh_new_group(dhg.g, dhg.p)); |
208 | } | 210 | } |
@@ -251,22 +253,22 @@ dh_pub_is_valid(DH *dh, BIGNUM *dh_pub) | |||
251 | return 0; | 253 | return 0; |
252 | } | 254 | } |
253 | 255 | ||
254 | void | 256 | int |
255 | dh_gen_key(DH *dh, int need) | 257 | dh_gen_key(DH *dh, int need) |
256 | { | 258 | { |
257 | int pbits; | 259 | int pbits; |
258 | 260 | ||
259 | if (need <= 0) | 261 | if (need < 0 || dh->p == NULL || |
260 | fatal("%s: need <= 0", __func__); | 262 | (pbits = BN_num_bits(dh->p)) <= 0 || |
261 | if (dh->p == NULL) | 263 | need > INT_MAX / 2 || 2 * need >= pbits) |
262 | fatal("%s: dh->p == NULL", __func__); | 264 | return SSH_ERR_INVALID_ARGUMENT; |
263 | if ((pbits = BN_num_bits(dh->p)) <= 0) | ||
264 | fatal("%s: bits(p) <= 0", __func__); | ||
265 | dh->length = MIN(need * 2, pbits - 1); | 265 | dh->length = MIN(need * 2, pbits - 1); |
266 | if (DH_generate_key(dh) == 0) | 266 | if (DH_generate_key(dh) == 0 || |
267 | fatal("%s: key generation failed", __func__); | 267 | !dh_pub_is_valid(dh, dh->pub_key)) { |
268 | if (!dh_pub_is_valid(dh, dh->pub_key)) | 268 | BN_clear_free(dh->priv_key); |
269 | fatal("%s: generated invalid key", __func__); | 269 | return SSH_ERR_LIBCRYPTO_ERROR; |
270 | } | ||
271 | return 0; | ||
270 | } | 272 | } |
271 | 273 | ||
272 | DH * | 274 | DH * |
@@ -275,13 +277,12 @@ dh_new_group_asc(const char *gen, const char *modulus) | |||
275 | DH *dh; | 277 | DH *dh; |
276 | 278 | ||
277 | if ((dh = DH_new()) == NULL) | 279 | if ((dh = DH_new()) == NULL) |
278 | fatal("dh_new_group_asc: DH_new"); | 280 | return NULL; |
279 | 281 | if (BN_hex2bn(&dh->p, modulus) == 0 || | |
280 | if (BN_hex2bn(&dh->p, modulus) == 0) | 282 | BN_hex2bn(&dh->g, gen) == 0) { |
281 | fatal("BN_hex2bn p"); | 283 | DH_free(dh); |
282 | if (BN_hex2bn(&dh->g, gen) == 0) | 284 | return NULL; |
283 | fatal("BN_hex2bn g"); | 285 | } |
284 | |||
285 | return (dh); | 286 | return (dh); |
286 | } | 287 | } |
287 | 288 | ||
@@ -296,7 +297,7 @@ dh_new_group(BIGNUM *gen, BIGNUM *modulus) | |||
296 | DH *dh; | 297 | DH *dh; |
297 | 298 | ||
298 | if ((dh = DH_new()) == NULL) | 299 | if ((dh = DH_new()) == NULL) |
299 | fatal("dh_new_group: DH_new"); | 300 | return NULL; |
300 | dh->p = modulus; | 301 | dh->p = modulus; |
301 | dh->g = gen; | 302 | dh->g = gen; |
302 | 303 | ||
@@ -344,7 +345,7 @@ dh_new_group14(void) | |||
344 | * from RFC4419 section 3. | 345 | * from RFC4419 section 3. |
345 | */ | 346 | */ |
346 | 347 | ||
347 | int | 348 | u_int |
348 | dh_estimate(int bits) | 349 | dh_estimate(int bits) |
349 | { | 350 | { |
350 | if (bits <= 112) | 351 | if (bits <= 112) |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dh.h,v 1.11 2013/10/08 11:42:13 dtucker Exp $ */ | 1 | /* $OpenBSD: dh.h,v 1.12 2015/01/19 20:16:15 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Niels Provos. All rights reserved. | 4 | * Copyright (c) 2000 Niels Provos. All rights reserved. |
@@ -38,10 +38,10 @@ DH *dh_new_group(BIGNUM *, BIGNUM *); | |||
38 | DH *dh_new_group1(void); | 38 | DH *dh_new_group1(void); |
39 | DH *dh_new_group14(void); | 39 | DH *dh_new_group14(void); |
40 | 40 | ||
41 | void dh_gen_key(DH *, int); | 41 | int dh_gen_key(DH *, int); |
42 | int dh_pub_is_valid(DH *, BIGNUM *); | 42 | int dh_pub_is_valid(DH *, BIGNUM *); |
43 | 43 | ||
44 | int dh_estimate(int); | 44 | u_int dh_estimate(int); |
45 | 45 | ||
46 | /* Min and max values from RFC4419. */ | 46 | /* Min and max values from RFC4419. */ |
47 | #define DH_GRP_MIN 1024 | 47 | #define DH_GRP_MIN 1024 |
@@ -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 |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.h,v 1.68 2015/01/19 20:07:45 markus Exp $ */ | 1 | /* $OpenBSD: kex.h,v 1.69 2015/01/19 20:16:15 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -30,8 +30,8 @@ | |||
30 | #include "buffer.h" /* XXX for typedef */ | 30 | #include "buffer.h" /* XXX for typedef */ |
31 | #include "key.h" /* XXX for typedef */ | 31 | #include "key.h" /* XXX for typedef */ |
32 | 32 | ||
33 | #if defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) | 33 | #ifdef WITH_LEAKMALLOC |
34 | #include <openssl/ec.h> | 34 | #include "leakmalloc.h" |
35 | #endif | 35 | #endif |
36 | 36 | ||
37 | #define KEX_COOKIE_LEN 16 | 37 | #define KEX_COOKIE_LEN 16 |
@@ -50,6 +50,8 @@ | |||
50 | #define COMP_ZLIB 1 | 50 | #define COMP_ZLIB 1 |
51 | #define COMP_DELAYED 2 | 51 | #define COMP_DELAYED 2 |
52 | 52 | ||
53 | #define CURVE25519_SIZE 32 | ||
54 | |||
53 | enum kex_init_proposals { | 55 | enum kex_init_proposals { |
54 | PROPOSAL_KEX_ALGS, | 56 | PROPOSAL_KEX_ALGS, |
55 | PROPOSAL_SERVER_HOST_KEY_ALGS, | 57 | PROPOSAL_SERVER_HOST_KEY_ALGS, |
@@ -82,12 +84,6 @@ enum kex_exchange { | |||
82 | 84 | ||
83 | #define KEX_INIT_SENT 0x0001 | 85 | #define KEX_INIT_SENT 0x0001 |
84 | 86 | ||
85 | typedef struct kex Kex; | ||
86 | typedef struct sshcomp Comp; | ||
87 | typedef struct sshmac Mac; | ||
88 | typedef struct sshenc Enc; | ||
89 | typedef struct newkeys Newkeys; | ||
90 | |||
91 | struct sshenc { | 87 | struct sshenc { |
92 | char *name; | 88 | char *name; |
93 | const struct sshcipher *cipher; | 89 | const struct sshcipher *cipher; |
@@ -106,8 +102,11 @@ struct sshcomp { | |||
106 | struct newkeys { | 102 | struct newkeys { |
107 | struct sshenc enc; | 103 | struct sshenc enc; |
108 | struct sshmac mac; | 104 | struct sshmac mac; |
109 | struct sshcomp comp; | 105 | struct sshcomp comp; |
110 | }; | 106 | }; |
107 | |||
108 | struct ssh; | ||
109 | |||
111 | struct kex { | 110 | struct kex { |
112 | u_char *session_id; | 111 | u_char *session_id; |
113 | size_t session_id_len; | 112 | size_t session_id_len; |
@@ -117,73 +116,87 @@ struct kex { | |||
117 | int server; | 116 | int server; |
118 | char *name; | 117 | char *name; |
119 | int hostkey_type; | 118 | int hostkey_type; |
120 | int kex_type; | 119 | u_int kex_type; |
121 | int roaming; | 120 | int roaming; |
122 | struct sshbuf *my; | 121 | struct sshbuf *my; |
123 | struct sshbuf *peer; | 122 | struct sshbuf *peer; |
124 | sig_atomic_t done; | 123 | sig_atomic_t done; |
125 | int flags; | 124 | u_int flags; |
126 | int hash_alg; | 125 | int hash_alg; |
127 | int ec_nid; | 126 | int ec_nid; |
128 | char *client_version_string; | 127 | char *client_version_string; |
129 | char *server_version_string; | 128 | char *server_version_string; |
130 | int (*verify_host_key)(Key *); | 129 | int (*verify_host_key)(struct sshkey *, struct ssh *); |
131 | Key *(*load_host_public_key)(int); | 130 | struct sshkey *(*load_host_public_key)(int, struct ssh *); |
132 | Key *(*load_host_private_key)(int); | 131 | struct sshkey *(*load_host_private_key)(int, struct ssh *); |
133 | int (*host_key_index)(Key *); | 132 | int (*host_key_index)(struct sshkey *, struct ssh *); |
134 | void (*sign)(Key *, Key *, u_char **, u_int *, u_char *, u_int); | 133 | int (*sign)(struct sshkey *, struct sshkey *, |
135 | void (*kex[KEX_MAX])(Kex *); | 134 | u_char **, size_t *, u_char *, size_t, u_int); |
135 | int (*kex[KEX_MAX])(struct ssh *); | ||
136 | /* kex specific state */ | ||
137 | DH *dh; /* DH */ | ||
138 | u_int min, max, nbits; /* GEX */ | ||
139 | EC_KEY *ec_client_key; /* ECDH */ | ||
140 | const EC_GROUP *ec_group; /* ECDH */ | ||
141 | u_char c25519_client_key[CURVE25519_SIZE]; /* 25519 */ | ||
142 | u_char c25519_client_pubkey[CURVE25519_SIZE]; /* 25519 */ | ||
136 | }; | 143 | }; |
137 | 144 | ||
138 | int kex_names_valid(const char *); | 145 | int kex_names_valid(const char *); |
139 | char *kex_alg_list(char); | 146 | char *kex_alg_list(char); |
140 | 147 | ||
141 | Kex *kex_setup(char *[PROPOSAL_MAX]); | 148 | int kex_new(struct ssh *, char *[PROPOSAL_MAX], struct kex **); |
142 | void kex_finish(Kex *); | 149 | int kex_setup(struct ssh *, char *[PROPOSAL_MAX]); |
143 | void kex_free_newkeys(struct newkeys *); | 150 | void kex_free_newkeys(struct newkeys *); |
151 | void kex_free(struct kex *); | ||
144 | 152 | ||
145 | void kex_send_kexinit(Kex *); | 153 | int kex_buf2prop(struct sshbuf *, int *, char ***); |
146 | int kex_input_kexinit(int, u_int32_t, void *); | 154 | int kex_prop2buf(struct sshbuf *, char *proposal[PROPOSAL_MAX]); |
147 | void kex_derive_keys(Kex *, u_char *, u_int, const u_char *, u_int); | 155 | void kex_prop_free(char **); |
148 | void kex_derive_keys_bn(Kex *, u_char *, u_int, const BIGNUM *); | ||
149 | |||
150 | void kexdh_client(Kex *); | ||
151 | void kexdh_server(Kex *); | ||
152 | void kexgex_client(Kex *); | ||
153 | void kexgex_server(Kex *); | ||
154 | void kexecdh_client(Kex *); | ||
155 | void kexecdh_server(Kex *); | ||
156 | void kexc25519_client(Kex *); | ||
157 | void kexc25519_server(Kex *); | ||
158 | |||
159 | void | ||
160 | kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int, | ||
161 | BIGNUM *, BIGNUM *, BIGNUM *, u_char **, u_int *); | ||
162 | void | ||
163 | kexgex_hash(int, char *, char *, char *, int, char *, | ||
164 | int, u_char *, int, int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, | ||
165 | BIGNUM *, BIGNUM *, u_char **, u_int *); | ||
166 | #ifdef OPENSSL_HAS_ECC | ||
167 | void | ||
168 | kex_ecdh_hash(int, const EC_GROUP *, char *, char *, char *, int, | ||
169 | char *, int, u_char *, int, const EC_POINT *, const EC_POINT *, | ||
170 | const BIGNUM *, u_char **, u_int *); | ||
171 | #endif | ||
172 | void | ||
173 | kex_c25519_hash(int, char *, char *, char *, int, | ||
174 | char *, int, u_char *, int, const u_char *, const u_char *, | ||
175 | const u_char *, u_int, u_char **, u_int *); | ||
176 | 156 | ||
177 | #define CURVE25519_SIZE 32 | 157 | int kex_send_kexinit(struct ssh *); |
178 | void kexc25519_keygen(u_char[CURVE25519_SIZE], u_char[CURVE25519_SIZE]) | 158 | int kex_input_kexinit(int, u_int32_t, void *); |
159 | int kex_derive_keys(struct ssh *, u_char *, u_int, const struct sshbuf *); | ||
160 | int kex_derive_keys_bn(struct ssh *, u_char *, u_int, const BIGNUM *); | ||
161 | int kex_send_newkeys(struct ssh *); | ||
162 | |||
163 | int kexdh_client(struct ssh *); | ||
164 | int kexdh_server(struct ssh *); | ||
165 | int kexgex_client(struct ssh *); | ||
166 | int kexgex_server(struct ssh *); | ||
167 | int kexecdh_client(struct ssh *); | ||
168 | int kexecdh_server(struct ssh *); | ||
169 | int kexc25519_client(struct ssh *); | ||
170 | int kexc25519_server(struct ssh *); | ||
171 | |||
172 | int kex_dh_hash(const char *, const char *, | ||
173 | const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, | ||
174 | const BIGNUM *, const BIGNUM *, const BIGNUM *, u_char *, size_t *); | ||
175 | |||
176 | int kexgex_hash(int, const char *, const char *, | ||
177 | const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, | ||
178 | int, int, int, | ||
179 | const BIGNUM *, const BIGNUM *, const BIGNUM *, | ||
180 | const BIGNUM *, const BIGNUM *, | ||
181 | u_char *, size_t *); | ||
182 | |||
183 | int kex_ecdh_hash(int, const EC_GROUP *, const char *, const char *, | ||
184 | const u_char *, size_t, const u_char *, size_t, const u_char *, size_t, | ||
185 | const EC_POINT *, const EC_POINT *, const BIGNUM *, u_char *, size_t *); | ||
186 | |||
187 | int kex_c25519_hash(int, const char *, const char *, const char *, size_t, | ||
188 | const char *, size_t, const u_char *, size_t, const u_char *, const u_char *, | ||
189 | const u_char *, size_t, u_char *, size_t *); | ||
190 | |||
191 | void kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) | ||
179 | __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) | 192 | __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) |
180 | __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); | 193 | __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); |
181 | void kexc25519_shared_key(const u_char key[CURVE25519_SIZE], | 194 | int kexc25519_shared_key(const u_char key[CURVE25519_SIZE], |
182 | const u_char pub[CURVE25519_SIZE], Buffer *out) | 195 | const u_char pub[CURVE25519_SIZE], struct sshbuf *out) |
183 | __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) | 196 | __attribute__((__bounded__(__minbytes__, 1, CURVE25519_SIZE))) |
184 | __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); | 197 | __attribute__((__bounded__(__minbytes__, 2, CURVE25519_SIZE))); |
185 | 198 | ||
186 | void | 199 | int |
187 | derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]); | 200 | derive_ssh1_session_id(BIGNUM *, BIGNUM *, u_int8_t[8], u_int8_t[16]); |
188 | 201 | ||
189 | #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) | 202 | #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) || defined(DEBUG_KEXECDH) |
diff --git a/kexc25519.c b/kexc25519.c index e3afa0055..b6e6c4010 100644 --- a/kexc25519.c +++ b/kexc25519.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexc25519.c,v 1.7 2014/05/02 03:27:54 djm Exp $ */ | 1 | /* $OpenBSD: kexc25519.c,v 1.8 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001, 2013 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001, 2013 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2010 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
@@ -35,13 +35,14 @@ | |||
35 | #include <openssl/bn.h> | 35 | #include <openssl/bn.h> |
36 | #include <openssl/evp.h> | 36 | #include <openssl/evp.h> |
37 | 37 | ||
38 | #include "buffer.h" | 38 | #include "sshbuf.h" |
39 | #include "ssh2.h" | 39 | #include "ssh2.h" |
40 | #include "key.h" | 40 | #include "sshkey.h" |
41 | #include "cipher.h" | 41 | #include "cipher.h" |
42 | #include "kex.h" | 42 | #include "kex.h" |
43 | #include "log.h" | 43 | #include "log.h" |
44 | #include "digest.h" | 44 | #include "digest.h" |
45 | #include "ssherr.h" | ||
45 | 46 | ||
46 | extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE], | 47 | extern int crypto_scalarmult_curve25519(u_char a[CURVE25519_SIZE], |
47 | const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE]) | 48 | const u_char b[CURVE25519_SIZE], const u_char c[CURVE25519_SIZE]) |
@@ -58,65 +59,70 @@ kexc25519_keygen(u_char key[CURVE25519_SIZE], u_char pub[CURVE25519_SIZE]) | |||
58 | crypto_scalarmult_curve25519(pub, key, basepoint); | 59 | crypto_scalarmult_curve25519(pub, key, basepoint); |
59 | } | 60 | } |
60 | 61 | ||
61 | void | 62 | int |
62 | kexc25519_shared_key(const u_char key[CURVE25519_SIZE], | 63 | kexc25519_shared_key(const u_char key[CURVE25519_SIZE], |
63 | const u_char pub[CURVE25519_SIZE], Buffer *out) | 64 | const u_char pub[CURVE25519_SIZE], struct sshbuf *out) |
64 | { | 65 | { |
65 | u_char shared_key[CURVE25519_SIZE]; | 66 | u_char shared_key[CURVE25519_SIZE]; |
67 | int r; | ||
66 | 68 | ||
67 | crypto_scalarmult_curve25519(shared_key, key, pub); | 69 | crypto_scalarmult_curve25519(shared_key, key, pub); |
68 | #ifdef DEBUG_KEXECDH | 70 | #ifdef DEBUG_KEXECDH |
69 | dump_digest("shared secret", shared_key, CURVE25519_SIZE); | 71 | dump_digest("shared secret", shared_key, CURVE25519_SIZE); |
70 | #endif | 72 | #endif |
71 | buffer_clear(out); | 73 | sshbuf_reset(out); |
72 | buffer_put_bignum2_from_string(out, shared_key, CURVE25519_SIZE); | 74 | r = sshbuf_put_bignum2_bytes(out, shared_key, CURVE25519_SIZE); |
73 | explicit_bzero(shared_key, CURVE25519_SIZE); | 75 | explicit_bzero(shared_key, CURVE25519_SIZE); |
76 | return r; | ||
74 | } | 77 | } |
75 | 78 | ||
76 | void | 79 | int |
77 | kex_c25519_hash( | 80 | kex_c25519_hash( |
78 | int hash_alg, | 81 | int hash_alg, |
79 | char *client_version_string, | 82 | const char *client_version_string, |
80 | char *server_version_string, | 83 | const char *server_version_string, |
81 | char *ckexinit, int ckexinitlen, | 84 | const char *ckexinit, size_t ckexinitlen, |
82 | char *skexinit, int skexinitlen, | 85 | const char *skexinit, size_t skexinitlen, |
83 | u_char *serverhostkeyblob, int sbloblen, | 86 | const u_char *serverhostkeyblob, size_t sbloblen, |
84 | const u_char client_dh_pub[CURVE25519_SIZE], | 87 | const u_char client_dh_pub[CURVE25519_SIZE], |
85 | const u_char server_dh_pub[CURVE25519_SIZE], | 88 | const u_char server_dh_pub[CURVE25519_SIZE], |
86 | const u_char *shared_secret, u_int secretlen, | 89 | const u_char *shared_secret, size_t secretlen, |
87 | u_char **hash, u_int *hashlen) | 90 | u_char *hash, size_t *hashlen) |
88 | { | 91 | { |
89 | Buffer b; | 92 | struct sshbuf *b; |
90 | static u_char digest[SSH_DIGEST_MAX_LENGTH]; | 93 | int r; |
91 | 94 | ||
92 | buffer_init(&b); | 95 | if (*hashlen < ssh_digest_bytes(hash_alg)) |
93 | buffer_put_cstring(&b, client_version_string); | 96 | return SSH_ERR_INVALID_ARGUMENT; |
94 | buffer_put_cstring(&b, server_version_string); | 97 | if ((b = sshbuf_new()) == NULL) |
95 | 98 | return SSH_ERR_ALLOC_FAIL; | |
96 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | 99 | if ((r = sshbuf_put_cstring(b, client_version_string)) < 0 || |
97 | buffer_put_int(&b, ckexinitlen+1); | 100 | (r = sshbuf_put_cstring(b, server_version_string)) < 0 || |
98 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | 101 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ |
99 | buffer_append(&b, ckexinit, ckexinitlen); | 102 | (r = sshbuf_put_u32(b, ckexinitlen+1)) < 0 || |
100 | buffer_put_int(&b, skexinitlen+1); | 103 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) < 0 || |
101 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | 104 | (r = sshbuf_put(b, ckexinit, ckexinitlen)) < 0 || |
102 | buffer_append(&b, skexinit, skexinitlen); | 105 | (r = sshbuf_put_u32(b, skexinitlen+1)) < 0 || |
103 | 106 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) < 0 || | |
104 | buffer_put_string(&b, serverhostkeyblob, sbloblen); | 107 | (r = sshbuf_put(b, skexinit, skexinitlen)) < 0 || |
105 | buffer_put_string(&b, client_dh_pub, CURVE25519_SIZE); | 108 | (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) < 0 || |
106 | buffer_put_string(&b, server_dh_pub, CURVE25519_SIZE); | 109 | (r = sshbuf_put_string(b, client_dh_pub, CURVE25519_SIZE)) < 0 || |
107 | buffer_append(&b, shared_secret, secretlen); | 110 | (r = sshbuf_put_string(b, server_dh_pub, CURVE25519_SIZE)) < 0 || |
108 | 111 | (r = sshbuf_put(b, shared_secret, secretlen)) < 0) { | |
112 | sshbuf_free(b); | ||
113 | return r; | ||
114 | } | ||
109 | #ifdef DEBUG_KEX | 115 | #ifdef DEBUG_KEX |
110 | buffer_dump(&b); | 116 | sshbuf_dump(b, stderr); |
111 | #endif | 117 | #endif |
112 | if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0) | 118 | if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { |
113 | fatal("%s: digest_buffer failed", __func__); | 119 | sshbuf_free(b); |
114 | 120 | return SSH_ERR_LIBCRYPTO_ERROR; | |
115 | buffer_free(&b); | 121 | } |
116 | 122 | sshbuf_free(b); | |
123 | *hashlen = ssh_digest_bytes(hash_alg); | ||
117 | #ifdef DEBUG_KEX | 124 | #ifdef DEBUG_KEX |
118 | dump_digest("hash", digest, ssh_digest_bytes(hash_alg)); | 125 | dump_digest("hash", hash, *hashlen); |
119 | #endif | 126 | #endif |
120 | *hash = digest; | 127 | return 0; |
121 | *hashlen = ssh_digest_bytes(hash_alg); | ||
122 | } | 128 | } |
diff --git a/kexc25519c.c b/kexc25519c.c index ffb537ef6..833ce0544 100644 --- a/kexc25519c.c +++ b/kexc25519c.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexc25519c.c,v 1.5 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: kexc25519c.c,v 1.6 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2010 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
@@ -33,97 +33,136 @@ | |||
33 | #include <string.h> | 33 | #include <string.h> |
34 | #include <signal.h> | 34 | #include <signal.h> |
35 | 35 | ||
36 | #include "xmalloc.h" | 36 | #include "sshkey.h" |
37 | #include "buffer.h" | ||
38 | #include "key.h" | ||
39 | #include "cipher.h" | 37 | #include "cipher.h" |
40 | #include "kex.h" | 38 | #include "kex.h" |
41 | #include "log.h" | 39 | #include "log.h" |
42 | #include "packet.h" | 40 | #include "packet.h" |
43 | #include "ssh2.h" | 41 | #include "ssh2.h" |
42 | #include "sshbuf.h" | ||
43 | #include "digest.h" | ||
44 | #include "ssherr.h" | ||
44 | 45 | ||
45 | void | 46 | static int |
46 | kexc25519_client(Kex *kex) | 47 | input_kex_c25519_reply(int type, u_int32_t seq, void *ctxt); |
47 | { | ||
48 | Key *server_host_key; | ||
49 | u_char client_key[CURVE25519_SIZE]; | ||
50 | u_char client_pubkey[CURVE25519_SIZE]; | ||
51 | u_char *server_pubkey = NULL; | ||
52 | u_char *server_host_key_blob = NULL, *signature = NULL; | ||
53 | u_char *hash; | ||
54 | u_int slen, sbloblen, hashlen; | ||
55 | Buffer shared_secret; | ||
56 | |||
57 | kexc25519_keygen(client_key, client_pubkey); | ||
58 | 48 | ||
59 | packet_start(SSH2_MSG_KEX_ECDH_INIT); | 49 | int |
60 | packet_put_string(client_pubkey, sizeof(client_pubkey)); | 50 | kexc25519_client(struct ssh *ssh) |
61 | packet_send(); | 51 | { |
62 | debug("sending SSH2_MSG_KEX_ECDH_INIT"); | 52 | struct kex *kex = ssh->kex; |
53 | int r; | ||
63 | 54 | ||
55 | kexc25519_keygen(kex->c25519_client_key, kex->c25519_client_pubkey); | ||
64 | #ifdef DEBUG_KEXECDH | 56 | #ifdef DEBUG_KEXECDH |
65 | dump_digest("client private key:", client_key, sizeof(client_key)); | 57 | dump_digest("client private key:", kex->c25519_client_key, |
58 | sizeof(kex->c25519_client_key)); | ||
66 | #endif | 59 | #endif |
60 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 || | ||
61 | (r = sshpkt_put_string(ssh, kex->c25519_client_pubkey, | ||
62 | sizeof(kex->c25519_client_pubkey))) != 0 || | ||
63 | (r = sshpkt_send(ssh)) != 0) | ||
64 | return r; | ||
67 | 65 | ||
68 | debug("expecting SSH2_MSG_KEX_ECDH_REPLY"); | 66 | debug("expecting SSH2_MSG_KEX_ECDH_REPLY"); |
69 | packet_read_expect(SSH2_MSG_KEX_ECDH_REPLY); | 67 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_c25519_reply); |
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int | ||
72 | input_kex_c25519_reply(int type, u_int32_t seq, void *ctxt) | ||
73 | { | ||
74 | struct ssh *ssh = ctxt; | ||
75 | struct kex *kex = ssh->kex; | ||
76 | struct sshkey *server_host_key = NULL; | ||
77 | struct sshbuf *shared_secret = NULL; | ||
78 | u_char *server_pubkey = NULL; | ||
79 | u_char *server_host_key_blob = NULL, *signature = NULL; | ||
80 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
81 | size_t slen, pklen, sbloblen, hashlen; | ||
82 | int r; | ||
83 | |||
84 | if (kex->verify_host_key == NULL) { | ||
85 | r = SSH_ERR_INVALID_ARGUMENT; | ||
86 | goto out; | ||
87 | } | ||
70 | 88 | ||
71 | /* hostkey */ | 89 | /* hostkey */ |
72 | server_host_key_blob = packet_get_string(&sbloblen); | 90 | if ((r = sshpkt_get_string(ssh, &server_host_key_blob, |
73 | server_host_key = key_from_blob(server_host_key_blob, sbloblen); | 91 | &sbloblen)) != 0 || |
74 | if (server_host_key == NULL) | 92 | (r = sshkey_from_blob(server_host_key_blob, sbloblen, |
75 | fatal("cannot decode server_host_key_blob"); | 93 | &server_host_key)) != 0) |
76 | if (server_host_key->type != kex->hostkey_type) | 94 | goto out; |
77 | fatal("type mismatch for decoded server_host_key_blob"); | 95 | if (server_host_key->type != kex->hostkey_type) { |
78 | if (kex->verify_host_key == NULL) | 96 | r = SSH_ERR_KEY_TYPE_MISMATCH; |
79 | fatal("cannot verify server_host_key"); | 97 | goto out; |
80 | if (kex->verify_host_key(server_host_key) == -1) | 98 | } |
81 | fatal("server_host_key verification failed"); | 99 | if (kex->verify_host_key(server_host_key, ssh) == -1) { |
100 | r = SSH_ERR_SIGNATURE_INVALID; | ||
101 | goto out; | ||
102 | } | ||
82 | 103 | ||
83 | /* Q_S, server public key */ | 104 | /* Q_S, server public key */ |
84 | server_pubkey = packet_get_string(&slen); | 105 | /* signed H */ |
85 | if (slen != CURVE25519_SIZE) | 106 | if ((r = sshpkt_get_string(ssh, &server_pubkey, &pklen)) != 0 || |
86 | fatal("Incorrect size for server Curve25519 pubkey: %d", slen); | 107 | (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || |
108 | (r = sshpkt_get_end(ssh)) != 0) | ||
109 | goto out; | ||
110 | if (pklen != CURVE25519_SIZE) { | ||
111 | r = SSH_ERR_SIGNATURE_INVALID; | ||
112 | goto out; | ||
113 | } | ||
87 | 114 | ||
88 | #ifdef DEBUG_KEXECDH | 115 | #ifdef DEBUG_KEXECDH |
89 | dump_digest("server public key:", server_pubkey, CURVE25519_SIZE); | 116 | dump_digest("server public key:", server_pubkey, CURVE25519_SIZE); |
90 | #endif | 117 | #endif |
91 | 118 | ||
92 | /* signed H */ | 119 | if ((shared_secret = sshbuf_new()) == NULL) { |
93 | signature = packet_get_string(&slen); | 120 | r = SSH_ERR_ALLOC_FAIL; |
94 | packet_check_eom(); | 121 | goto out; |
95 | 122 | } | |
96 | buffer_init(&shared_secret); | 123 | if ((r = kexc25519_shared_key(kex->c25519_client_key, server_pubkey, |
97 | kexc25519_shared_key(client_key, server_pubkey, &shared_secret); | 124 | shared_secret)) < 0) |
125 | goto out; | ||
98 | 126 | ||
99 | /* calc and verify H */ | 127 | /* calc and verify H */ |
100 | kex_c25519_hash( | 128 | hashlen = sizeof(hash); |
129 | if ((r = kex_c25519_hash( | ||
101 | kex->hash_alg, | 130 | kex->hash_alg, |
102 | kex->client_version_string, | 131 | kex->client_version_string, |
103 | kex->server_version_string, | 132 | kex->server_version_string, |
104 | buffer_ptr(kex->my), buffer_len(kex->my), | 133 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), |
105 | buffer_ptr(kex->peer), buffer_len(kex->peer), | 134 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), |
106 | server_host_key_blob, sbloblen, | 135 | server_host_key_blob, sbloblen, |
107 | client_pubkey, | 136 | kex->c25519_client_pubkey, |
108 | server_pubkey, | 137 | server_pubkey, |
109 | buffer_ptr(&shared_secret), buffer_len(&shared_secret), | 138 | sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), |
110 | &hash, &hashlen | 139 | hash, &hashlen)) < 0) |
111 | ); | 140 | goto out; |
112 | free(server_host_key_blob); | 141 | |
113 | free(server_pubkey); | 142 | if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, |
114 | if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) | 143 | ssh->compat)) != 0) |
115 | fatal("key_verify failed for server_host_key"); | 144 | goto out; |
116 | key_free(server_host_key); | ||
117 | free(signature); | ||
118 | 145 | ||
119 | /* save session id */ | 146 | /* save session id */ |
120 | if (kex->session_id == NULL) { | 147 | if (kex->session_id == NULL) { |
121 | kex->session_id_len = hashlen; | 148 | kex->session_id_len = hashlen; |
122 | kex->session_id = xmalloc(kex->session_id_len); | 149 | kex->session_id = malloc(kex->session_id_len); |
150 | if (kex->session_id == NULL) { | ||
151 | r = SSH_ERR_ALLOC_FAIL; | ||
152 | goto out; | ||
153 | } | ||
123 | memcpy(kex->session_id, hash, kex->session_id_len); | 154 | memcpy(kex->session_id, hash, kex->session_id_len); |
124 | } | 155 | } |
125 | kex_derive_keys(kex, hash, hashlen, | 156 | |
126 | buffer_ptr(&shared_secret), buffer_len(&shared_secret)); | 157 | if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) |
127 | buffer_free(&shared_secret); | 158 | r = kex_send_newkeys(ssh); |
128 | kex_finish(kex); | 159 | out: |
160 | explicit_bzero(hash, sizeof(hash)); | ||
161 | explicit_bzero(kex->c25519_client_key, sizeof(kex->c25519_client_key)); | ||
162 | free(server_host_key_blob); | ||
163 | free(server_pubkey); | ||
164 | free(signature); | ||
165 | sshkey_free(server_host_key); | ||
166 | sshbuf_free(shared_secret); | ||
167 | return r; | ||
129 | } | 168 | } |
diff --git a/kexc25519s.c b/kexc25519s.c index ba6f546f4..912b0afb1 100644 --- a/kexc25519s.c +++ b/kexc25519s.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexc25519s.c,v 1.5 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: kexc25519s.c,v 1.6 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2010 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
@@ -30,97 +30,128 @@ | |||
30 | #include <string.h> | 30 | #include <string.h> |
31 | #include <signal.h> | 31 | #include <signal.h> |
32 | 32 | ||
33 | #include "xmalloc.h" | 33 | #include "sshkey.h" |
34 | #include "buffer.h" | ||
35 | #include "key.h" | ||
36 | #include "cipher.h" | 34 | #include "cipher.h" |
35 | #include "digest.h" | ||
37 | #include "kex.h" | 36 | #include "kex.h" |
38 | #include "log.h" | 37 | #include "log.h" |
39 | #include "packet.h" | 38 | #include "packet.h" |
40 | #include "ssh2.h" | 39 | #include "ssh2.h" |
40 | #include "sshbuf.h" | ||
41 | #include "ssherr.h" | ||
41 | 42 | ||
42 | void | 43 | static int input_kex_c25519_init(int, u_int32_t, void *); |
43 | kexc25519_server(Kex *kex) | 44 | |
45 | int | ||
46 | kexc25519_server(struct ssh *ssh) | ||
47 | { | ||
48 | debug("expecting SSH2_MSG_KEX_ECDH_INIT"); | ||
49 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_c25519_init); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int | ||
54 | input_kex_c25519_init(int type, u_int32_t seq, void *ctxt) | ||
44 | { | 55 | { |
45 | Key *server_host_private, *server_host_public; | 56 | struct ssh *ssh = ctxt; |
57 | struct kex *kex = ssh->kex; | ||
58 | struct sshkey *server_host_private, *server_host_public; | ||
59 | struct sshbuf *shared_secret = NULL; | ||
46 | u_char *server_host_key_blob = NULL, *signature = NULL; | 60 | u_char *server_host_key_blob = NULL, *signature = NULL; |
47 | u_char server_key[CURVE25519_SIZE]; | 61 | u_char server_key[CURVE25519_SIZE]; |
48 | u_char *client_pubkey = NULL; | 62 | u_char *client_pubkey = NULL; |
49 | u_char server_pubkey[CURVE25519_SIZE]; | 63 | u_char server_pubkey[CURVE25519_SIZE]; |
50 | u_char *hash; | 64 | u_char hash[SSH_DIGEST_MAX_LENGTH]; |
51 | u_int slen, sbloblen, hashlen; | 65 | size_t slen, pklen, sbloblen, hashlen; |
52 | Buffer shared_secret; | 66 | int r; |
53 | 67 | ||
54 | /* generate private key */ | 68 | /* generate private key */ |
55 | kexc25519_keygen(server_key, server_pubkey); | 69 | kexc25519_keygen(server_key, server_pubkey); |
56 | #ifdef DEBUG_KEXECDH | 70 | #ifdef DEBUG_KEXECDH |
57 | dump_digest("server private key:", server_key, sizeof(server_key)); | 71 | dump_digest("server private key:", server_key, sizeof(server_key)); |
58 | #endif | 72 | #endif |
59 | |||
60 | if (kex->load_host_public_key == NULL || | 73 | if (kex->load_host_public_key == NULL || |
61 | kex->load_host_private_key == NULL) | 74 | kex->load_host_private_key == NULL) { |
62 | fatal("Cannot load hostkey"); | 75 | r = SSH_ERR_INVALID_ARGUMENT; |
63 | server_host_public = kex->load_host_public_key(kex->hostkey_type); | 76 | goto out; |
64 | if (server_host_public == NULL) | 77 | } |
65 | fatal("Unsupported hostkey type %d", kex->hostkey_type); | 78 | if ((server_host_public = kex->load_host_public_key(kex->hostkey_type, |
66 | server_host_private = kex->load_host_private_key(kex->hostkey_type); | 79 | ssh)) == NULL || |
67 | 80 | (server_host_private = kex->load_host_private_key(kex->hostkey_type, | |
68 | debug("expecting SSH2_MSG_KEX_ECDH_INIT"); | 81 | ssh)) == NULL) { |
69 | packet_read_expect(SSH2_MSG_KEX_ECDH_INIT); | 82 | r = SSH_ERR_NO_HOSTKEY_LOADED; |
70 | client_pubkey = packet_get_string(&slen); | 83 | goto out; |
71 | if (slen != CURVE25519_SIZE) | 84 | } |
72 | fatal("Incorrect size for server Curve25519 pubkey: %d", slen); | ||
73 | packet_check_eom(); | ||
74 | 85 | ||
86 | if ((r = sshpkt_get_string(ssh, &client_pubkey, &pklen)) != 0 || | ||
87 | (r = sshpkt_get_end(ssh)) != 0) | ||
88 | goto out; | ||
89 | if (pklen != CURVE25519_SIZE) { | ||
90 | r = SSH_ERR_SIGNATURE_INVALID; | ||
91 | goto out; | ||
92 | } | ||
75 | #ifdef DEBUG_KEXECDH | 93 | #ifdef DEBUG_KEXECDH |
76 | dump_digest("client public key:", client_pubkey, CURVE25519_SIZE); | 94 | dump_digest("client public key:", client_pubkey, CURVE25519_SIZE); |
77 | #endif | 95 | #endif |
78 | 96 | ||
79 | buffer_init(&shared_secret); | 97 | if ((shared_secret = sshbuf_new()) == NULL) { |
80 | kexc25519_shared_key(server_key, client_pubkey, &shared_secret); | 98 | r = SSH_ERR_ALLOC_FAIL; |
99 | goto out; | ||
100 | } | ||
101 | if ((r = kexc25519_shared_key(server_key, client_pubkey, | ||
102 | shared_secret)) < 0) | ||
103 | goto out; | ||
81 | 104 | ||
82 | /* calc H */ | 105 | /* calc H */ |
83 | key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); | 106 | if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, |
84 | kex_c25519_hash( | 107 | &sbloblen)) != 0) |
108 | goto out; | ||
109 | hashlen = sizeof(hash); | ||
110 | if ((r = kex_c25519_hash( | ||
85 | kex->hash_alg, | 111 | kex->hash_alg, |
86 | kex->client_version_string, | 112 | kex->client_version_string, |
87 | kex->server_version_string, | 113 | kex->server_version_string, |
88 | buffer_ptr(kex->peer), buffer_len(kex->peer), | 114 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), |
89 | buffer_ptr(kex->my), buffer_len(kex->my), | 115 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), |
90 | server_host_key_blob, sbloblen, | 116 | server_host_key_blob, sbloblen, |
91 | client_pubkey, | 117 | client_pubkey, |
92 | server_pubkey, | 118 | server_pubkey, |
93 | buffer_ptr(&shared_secret), buffer_len(&shared_secret), | 119 | sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), |
94 | &hash, &hashlen | 120 | hash, &hashlen)) < 0) |
95 | ); | 121 | goto out; |
96 | 122 | ||
97 | /* save session id := H */ | 123 | /* save session id := H */ |
98 | if (kex->session_id == NULL) { | 124 | if (kex->session_id == NULL) { |
99 | kex->session_id_len = hashlen; | 125 | kex->session_id_len = hashlen; |
100 | kex->session_id = xmalloc(kex->session_id_len); | 126 | kex->session_id = malloc(kex->session_id_len); |
127 | if (kex->session_id == NULL) { | ||
128 | r = SSH_ERR_ALLOC_FAIL; | ||
129 | goto out; | ||
130 | } | ||
101 | memcpy(kex->session_id, hash, kex->session_id_len); | 131 | memcpy(kex->session_id, hash, kex->session_id_len); |
102 | } | 132 | } |
103 | 133 | ||
104 | /* sign H */ | 134 | /* sign H */ |
105 | kex->sign(server_host_private, server_host_public, &signature, &slen, | 135 | if ((r = kex->sign(server_host_private, server_host_public, |
106 | hash, hashlen); | 136 | &signature, &slen, hash, hashlen, ssh->compat)) < 0) |
107 | 137 | goto out; | |
108 | /* destroy_sensitive_data(); */ | ||
109 | 138 | ||
110 | /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ | 139 | /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ |
111 | packet_start(SSH2_MSG_KEX_ECDH_REPLY); | 140 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 || |
112 | packet_put_string(server_host_key_blob, sbloblen); | 141 | (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || |
113 | packet_put_string(server_pubkey, sizeof(server_pubkey)); | 142 | (r = sshpkt_put_string(ssh, server_pubkey, sizeof(server_pubkey))) != 0 || |
114 | packet_put_string(signature, slen); | 143 | (r = sshpkt_put_string(ssh, signature, slen)) != 0 || |
115 | packet_send(); | 144 | (r = sshpkt_send(ssh)) != 0) |
116 | 145 | goto out; | |
117 | free(signature); | 146 | |
147 | if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) | ||
148 | r = kex_send_newkeys(ssh); | ||
149 | out: | ||
150 | explicit_bzero(hash, sizeof(hash)); | ||
151 | explicit_bzero(server_key, sizeof(server_key)); | ||
118 | free(server_host_key_blob); | 152 | free(server_host_key_blob); |
119 | /* have keys, free server key */ | 153 | free(signature); |
120 | free(client_pubkey); | 154 | free(client_pubkey); |
121 | 155 | sshbuf_free(shared_secret); | |
122 | kex_derive_keys(kex, hash, hashlen, | 156 | return r; |
123 | buffer_ptr(&shared_secret), buffer_len(&shared_secret)); | ||
124 | buffer_free(&shared_secret); | ||
125 | kex_finish(kex); | ||
126 | } | 157 | } |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexdh.c,v 1.24 2014/01/09 23:20:00 djm Exp $ */ | 1 | /* $OpenBSD: kexdh.c,v 1.25 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -33,58 +33,61 @@ | |||
33 | 33 | ||
34 | #include <openssl/evp.h> | 34 | #include <openssl/evp.h> |
35 | 35 | ||
36 | #include "buffer.h" | ||
37 | #include "ssh2.h" | 36 | #include "ssh2.h" |
38 | #include "key.h" | 37 | #include "sshkey.h" |
39 | #include "cipher.h" | 38 | #include "cipher.h" |
40 | #include "kex.h" | 39 | #include "kex.h" |
40 | #include "ssherr.h" | ||
41 | #include "sshbuf.h" | ||
41 | #include "digest.h" | 42 | #include "digest.h" |
42 | #include "log.h" | ||
43 | 43 | ||
44 | void | 44 | int |
45 | kex_dh_hash( | 45 | kex_dh_hash( |
46 | char *client_version_string, | 46 | const char *client_version_string, |
47 | char *server_version_string, | 47 | const char *server_version_string, |
48 | char *ckexinit, int ckexinitlen, | 48 | const u_char *ckexinit, size_t ckexinitlen, |
49 | char *skexinit, int skexinitlen, | 49 | const u_char *skexinit, size_t skexinitlen, |
50 | u_char *serverhostkeyblob, int sbloblen, | 50 | const u_char *serverhostkeyblob, size_t sbloblen, |
51 | BIGNUM *client_dh_pub, | 51 | const BIGNUM *client_dh_pub, |
52 | BIGNUM *server_dh_pub, | 52 | const BIGNUM *server_dh_pub, |
53 | BIGNUM *shared_secret, | 53 | const BIGNUM *shared_secret, |
54 | u_char **hash, u_int *hashlen) | 54 | u_char *hash, size_t *hashlen) |
55 | { | 55 | { |
56 | Buffer b; | 56 | struct sshbuf *b; |
57 | static u_char digest[SSH_DIGEST_MAX_LENGTH]; | 57 | int r; |
58 | |||
59 | buffer_init(&b); | ||
60 | buffer_put_cstring(&b, client_version_string); | ||
61 | buffer_put_cstring(&b, server_version_string); | ||
62 | |||
63 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | ||
64 | buffer_put_int(&b, ckexinitlen+1); | ||
65 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | ||
66 | buffer_append(&b, ckexinit, ckexinitlen); | ||
67 | buffer_put_int(&b, skexinitlen+1); | ||
68 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | ||
69 | buffer_append(&b, skexinit, skexinitlen); | ||
70 | |||
71 | buffer_put_string(&b, serverhostkeyblob, sbloblen); | ||
72 | buffer_put_bignum2(&b, client_dh_pub); | ||
73 | buffer_put_bignum2(&b, server_dh_pub); | ||
74 | buffer_put_bignum2(&b, shared_secret); | ||
75 | 58 | ||
59 | if (*hashlen < ssh_digest_bytes(SSH_DIGEST_SHA1)) | ||
60 | return SSH_ERR_INVALID_ARGUMENT; | ||
61 | if ((b = sshbuf_new()) == NULL) | ||
62 | return SSH_ERR_ALLOC_FAIL; | ||
63 | if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 || | ||
64 | (r = sshbuf_put_cstring(b, server_version_string)) != 0 || | ||
65 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | ||
66 | (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 || | ||
67 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || | ||
68 | (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 || | ||
69 | (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 || | ||
70 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || | ||
71 | (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || | ||
72 | (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || | ||
73 | (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 || | ||
74 | (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 || | ||
75 | (r = sshbuf_put_bignum2(b, shared_secret)) != 0) { | ||
76 | sshbuf_free(b); | ||
77 | return r; | ||
78 | } | ||
76 | #ifdef DEBUG_KEX | 79 | #ifdef DEBUG_KEX |
77 | buffer_dump(&b); | 80 | sshbuf_dump(b, stderr); |
78 | #endif | 81 | #endif |
79 | if (ssh_digest_buffer(SSH_DIGEST_SHA1, &b, digest, sizeof(digest)) != 0) | 82 | if (ssh_digest_buffer(SSH_DIGEST_SHA1, b, hash, *hashlen) != 0) { |
80 | fatal("%s: ssh_digest_buffer failed", __func__); | 83 | sshbuf_free(b); |
81 | 84 | return SSH_ERR_LIBCRYPTO_ERROR; | |
82 | buffer_free(&b); | 85 | } |
83 | 86 | sshbuf_free(b); | |
87 | *hashlen = ssh_digest_bytes(SSH_DIGEST_SHA1); | ||
84 | #ifdef DEBUG_KEX | 88 | #ifdef DEBUG_KEX |
85 | dump_digest("hash", digest, ssh_digest_bytes(SSH_DIGEST_SHA1)); | 89 | dump_digest("hash", hash, *hashlen); |
86 | #endif | 90 | #endif |
87 | *hash = digest; | 91 | return 0; |
88 | *hashlen = ssh_digest_bytes(SSH_DIGEST_SHA1); | ||
89 | } | 92 | } |
90 | #endif /* WITH_OPENSSL */ | 93 | #endif /* WITH_OPENSSL */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexdhc.c,v 1.16 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: kexdhc.c,v 1.17 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -36,129 +36,175 @@ | |||
36 | #include <string.h> | 36 | #include <string.h> |
37 | #include <signal.h> | 37 | #include <signal.h> |
38 | 38 | ||
39 | #include "xmalloc.h" | 39 | #include "sshkey.h" |
40 | #include "buffer.h" | ||
41 | #include "key.h" | ||
42 | #include "cipher.h" | 40 | #include "cipher.h" |
41 | #include "digest.h" | ||
43 | #include "kex.h" | 42 | #include "kex.h" |
44 | #include "log.h" | 43 | #include "log.h" |
45 | #include "packet.h" | 44 | #include "packet.h" |
46 | #include "dh.h" | 45 | #include "dh.h" |
47 | #include "ssh2.h" | 46 | #include "ssh2.h" |
47 | #include "dispatch.h" | ||
48 | #include "compat.h" | ||
49 | #include "ssherr.h" | ||
50 | #include "sshbuf.h" | ||
48 | 51 | ||
49 | void | 52 | static int input_kex_dh(int, u_int32_t, void *); |
50 | kexdh_client(Kex *kex) | 53 | |
54 | int | ||
55 | kexdh_client(struct ssh *ssh) | ||
51 | { | 56 | { |
52 | BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; | 57 | struct kex *kex = ssh->kex; |
53 | DH *dh; | 58 | int r; |
54 | Key *server_host_key; | ||
55 | u_char *server_host_key_blob = NULL, *signature = NULL; | ||
56 | u_char *kbuf, *hash; | ||
57 | u_int klen, slen, sbloblen, hashlen; | ||
58 | int kout; | ||
59 | 59 | ||
60 | /* generate and send 'e', client DH public key */ | 60 | /* generate and send 'e', client DH public key */ |
61 | switch (kex->kex_type) { | 61 | switch (kex->kex_type) { |
62 | case KEX_DH_GRP1_SHA1: | 62 | case KEX_DH_GRP1_SHA1: |
63 | dh = dh_new_group1(); | 63 | kex->dh = dh_new_group1(); |
64 | break; | 64 | break; |
65 | case KEX_DH_GRP14_SHA1: | 65 | case KEX_DH_GRP14_SHA1: |
66 | dh = dh_new_group14(); | 66 | kex->dh = dh_new_group14(); |
67 | break; | 67 | break; |
68 | default: | 68 | default: |
69 | fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | 69 | r = SSH_ERR_INVALID_ARGUMENT; |
70 | goto out; | ||
71 | } | ||
72 | if (kex->dh == NULL) { | ||
73 | r = SSH_ERR_ALLOC_FAIL; | ||
74 | goto out; | ||
70 | } | 75 | } |
71 | dh_gen_key(dh, kex->we_need * 8); | ||
72 | packet_start(SSH2_MSG_KEXDH_INIT); | ||
73 | packet_put_bignum2(dh->pub_key); | ||
74 | packet_send(); | ||
75 | |||
76 | debug("sending SSH2_MSG_KEXDH_INIT"); | 76 | debug("sending SSH2_MSG_KEXDH_INIT"); |
77 | if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || | ||
78 | (r = sshpkt_start(ssh, SSH2_MSG_KEXDH_INIT)) != 0 || | ||
79 | (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || | ||
80 | (r = sshpkt_send(ssh)) != 0) | ||
81 | goto out; | ||
77 | #ifdef DEBUG_KEXDH | 82 | #ifdef DEBUG_KEXDH |
78 | DHparams_print_fp(stderr, dh); | 83 | DHparams_print_fp(stderr, kex->dh); |
79 | fprintf(stderr, "pub= "); | 84 | fprintf(stderr, "pub= "); |
80 | BN_print_fp(stderr, dh->pub_key); | 85 | BN_print_fp(stderr, kex->dh->pub_key); |
81 | fprintf(stderr, "\n"); | 86 | fprintf(stderr, "\n"); |
82 | #endif | 87 | #endif |
83 | |||
84 | debug("expecting SSH2_MSG_KEXDH_REPLY"); | 88 | debug("expecting SSH2_MSG_KEXDH_REPLY"); |
85 | packet_read_expect(SSH2_MSG_KEXDH_REPLY); | 89 | ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_REPLY, &input_kex_dh); |
90 | r = 0; | ||
91 | out: | ||
92 | return r; | ||
93 | } | ||
86 | 94 | ||
95 | static int | ||
96 | input_kex_dh(int type, u_int32_t seq, void *ctxt) | ||
97 | { | ||
98 | struct ssh *ssh = ctxt; | ||
99 | struct kex *kex = ssh->kex; | ||
100 | BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; | ||
101 | struct sshkey *server_host_key = NULL; | ||
102 | u_char *kbuf = NULL, *server_host_key_blob = NULL, *signature = NULL; | ||
103 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
104 | size_t klen = 0, slen, sbloblen, hashlen; | ||
105 | int kout, r; | ||
106 | |||
107 | if (kex->verify_host_key == NULL) { | ||
108 | r = SSH_ERR_INVALID_ARGUMENT; | ||
109 | goto out; | ||
110 | } | ||
87 | /* key, cert */ | 111 | /* key, cert */ |
88 | server_host_key_blob = packet_get_string(&sbloblen); | 112 | if ((r = sshpkt_get_string(ssh, &server_host_key_blob, |
89 | server_host_key = key_from_blob(server_host_key_blob, sbloblen); | 113 | &sbloblen)) != 0 || |
90 | if (server_host_key == NULL) | 114 | (r = sshkey_from_blob(server_host_key_blob, sbloblen, |
91 | fatal("cannot decode server_host_key_blob"); | 115 | &server_host_key)) != 0) |
92 | if (server_host_key->type != kex->hostkey_type) | 116 | goto out; |
93 | fatal("type mismatch for decoded server_host_key_blob"); | 117 | if (server_host_key->type != kex->hostkey_type) { |
94 | if (kex->verify_host_key == NULL) | 118 | r = SSH_ERR_KEY_TYPE_MISMATCH; |
95 | fatal("cannot verify server_host_key"); | 119 | goto out; |
96 | if (kex->verify_host_key(server_host_key) == -1) | 120 | } |
97 | fatal("server_host_key verification failed"); | 121 | if (kex->verify_host_key(server_host_key, ssh) == -1) { |
98 | 122 | r = SSH_ERR_SIGNATURE_INVALID; | |
123 | goto out; | ||
124 | } | ||
99 | /* DH parameter f, server public DH key */ | 125 | /* DH parameter f, server public DH key */ |
100 | if ((dh_server_pub = BN_new()) == NULL) | 126 | if ((dh_server_pub = BN_new()) == NULL) { |
101 | fatal("dh_server_pub == NULL"); | 127 | r = SSH_ERR_ALLOC_FAIL; |
102 | packet_get_bignum2(dh_server_pub); | 128 | goto out; |
103 | 129 | } | |
130 | /* signed H */ | ||
131 | if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || | ||
132 | (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || | ||
133 | (r = sshpkt_get_end(ssh)) != 0) | ||
134 | goto out; | ||
104 | #ifdef DEBUG_KEXDH | 135 | #ifdef DEBUG_KEXDH |
105 | fprintf(stderr, "dh_server_pub= "); | 136 | fprintf(stderr, "dh_server_pub= "); |
106 | BN_print_fp(stderr, dh_server_pub); | 137 | BN_print_fp(stderr, dh_server_pub); |
107 | fprintf(stderr, "\n"); | 138 | fprintf(stderr, "\n"); |
108 | debug("bits %d", BN_num_bits(dh_server_pub)); | 139 | debug("bits %d", BN_num_bits(dh_server_pub)); |
109 | #endif | 140 | #endif |
141 | if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { | ||
142 | sshpkt_disconnect(ssh, "bad server public DH value"); | ||
143 | r = SSH_ERR_MESSAGE_INCOMPLETE; | ||
144 | goto out; | ||
145 | } | ||
110 | 146 | ||
111 | /* signed H */ | 147 | klen = DH_size(kex->dh); |
112 | signature = packet_get_string(&slen); | 148 | if ((kbuf = malloc(klen)) == NULL || |
113 | packet_check_eom(); | 149 | (shared_secret = BN_new()) == NULL) { |
114 | 150 | r = SSH_ERR_ALLOC_FAIL; | |
115 | if (!dh_pub_is_valid(dh, dh_server_pub)) | 151 | goto out; |
116 | packet_disconnect("bad server public DH value"); | 152 | } |
117 | 153 | if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || | |
118 | klen = DH_size(dh); | 154 | BN_bin2bn(kbuf, kout, shared_secret) == NULL) { |
119 | kbuf = xmalloc(klen); | 155 | r = SSH_ERR_LIBCRYPTO_ERROR; |
120 | if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0) | 156 | goto out; |
121 | fatal("DH_compute_key: failed"); | 157 | } |
122 | #ifdef DEBUG_KEXDH | 158 | #ifdef DEBUG_KEXDH |
123 | dump_digest("shared secret", kbuf, kout); | 159 | dump_digest("shared secret", kbuf, kout); |
124 | #endif | 160 | #endif |
125 | if ((shared_secret = BN_new()) == NULL) | ||
126 | fatal("kexdh_client: BN_new failed"); | ||
127 | if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) | ||
128 | fatal("kexdh_client: BN_bin2bn failed"); | ||
129 | explicit_bzero(kbuf, klen); | ||
130 | free(kbuf); | ||
131 | 161 | ||
132 | /* calc and verify H */ | 162 | /* calc and verify H */ |
133 | kex_dh_hash( | 163 | hashlen = sizeof(hash); |
164 | if ((r = kex_dh_hash( | ||
134 | kex->client_version_string, | 165 | kex->client_version_string, |
135 | kex->server_version_string, | 166 | kex->server_version_string, |
136 | buffer_ptr(kex->my), buffer_len(kex->my), | 167 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), |
137 | buffer_ptr(kex->peer), buffer_len(kex->peer), | 168 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), |
138 | server_host_key_blob, sbloblen, | 169 | server_host_key_blob, sbloblen, |
139 | dh->pub_key, | 170 | kex->dh->pub_key, |
140 | dh_server_pub, | 171 | dh_server_pub, |
141 | shared_secret, | 172 | shared_secret, |
142 | &hash, &hashlen | 173 | hash, &hashlen)) != 0) |
143 | ); | 174 | goto out; |
144 | free(server_host_key_blob); | ||
145 | BN_clear_free(dh_server_pub); | ||
146 | DH_free(dh); | ||
147 | 175 | ||
148 | if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) | 176 | if ((r = sshkey_verify(server_host_key, signature, slen, hash, hashlen, |
149 | fatal("key_verify failed for server_host_key"); | 177 | ssh->compat)) != 0) |
150 | key_free(server_host_key); | 178 | goto out; |
151 | free(signature); | ||
152 | 179 | ||
153 | /* save session id */ | 180 | /* save session id */ |
154 | if (kex->session_id == NULL) { | 181 | if (kex->session_id == NULL) { |
155 | kex->session_id_len = hashlen; | 182 | kex->session_id_len = hashlen; |
156 | kex->session_id = xmalloc(kex->session_id_len); | 183 | kex->session_id = malloc(kex->session_id_len); |
184 | if (kex->session_id == NULL) { | ||
185 | r = SSH_ERR_ALLOC_FAIL; | ||
186 | goto out; | ||
187 | } | ||
157 | memcpy(kex->session_id, hash, kex->session_id_len); | 188 | memcpy(kex->session_id, hash, kex->session_id_len); |
158 | } | 189 | } |
159 | 190 | ||
160 | kex_derive_keys_bn(kex, hash, hashlen, shared_secret); | 191 | if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) |
161 | BN_clear_free(shared_secret); | 192 | r = kex_send_newkeys(ssh); |
162 | kex_finish(kex); | 193 | out: |
194 | explicit_bzero(hash, sizeof(hash)); | ||
195 | DH_free(kex->dh); | ||
196 | kex->dh = NULL; | ||
197 | if (dh_server_pub) | ||
198 | BN_clear_free(dh_server_pub); | ||
199 | if (kbuf) { | ||
200 | explicit_bzero(kbuf, klen); | ||
201 | free(kbuf); | ||
202 | } | ||
203 | if (shared_secret) | ||
204 | BN_clear_free(shared_secret); | ||
205 | sshkey_free(server_host_key); | ||
206 | free(server_host_key_blob); | ||
207 | free(signature); | ||
208 | return r; | ||
163 | } | 209 | } |
164 | #endif /* WITH_OPENSSL */ | 210 | #endif /* WITH_OPENSSL */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexdhs.c,v 1.19 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: kexdhs.c,v 1.20 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * | 4 | * |
@@ -35,55 +35,88 @@ | |||
35 | 35 | ||
36 | #include <openssl/dh.h> | 36 | #include <openssl/dh.h> |
37 | 37 | ||
38 | #include "xmalloc.h" | 38 | #include "sshkey.h" |
39 | #include "buffer.h" | ||
40 | #include "key.h" | ||
41 | #include "cipher.h" | 39 | #include "cipher.h" |
40 | #include "digest.h" | ||
42 | #include "kex.h" | 41 | #include "kex.h" |
43 | #include "log.h" | 42 | #include "log.h" |
44 | #include "packet.h" | 43 | #include "packet.h" |
45 | #include "dh.h" | 44 | #include "dh.h" |
46 | #include "ssh2.h" | 45 | #include "ssh2.h" |
47 | 46 | ||
48 | void | 47 | #include "dispatch.h" |
49 | kexdh_server(Kex *kex) | 48 | #include "compat.h" |
49 | #include "ssherr.h" | ||
50 | #include "sshbuf.h" | ||
51 | |||
52 | static int input_kex_dh_init(int, u_int32_t, void *); | ||
53 | |||
54 | int | ||
55 | kexdh_server(struct ssh *ssh) | ||
50 | { | 56 | { |
51 | BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; | 57 | struct kex *kex = ssh->kex; |
52 | DH *dh; | 58 | int r; |
53 | Key *server_host_public, *server_host_private; | ||
54 | u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; | ||
55 | u_int sbloblen, klen, hashlen, slen; | ||
56 | int kout; | ||
57 | 59 | ||
58 | /* generate server DH public key */ | 60 | /* generate server DH public key */ |
59 | switch (kex->kex_type) { | 61 | switch (kex->kex_type) { |
60 | case KEX_DH_GRP1_SHA1: | 62 | case KEX_DH_GRP1_SHA1: |
61 | dh = dh_new_group1(); | 63 | kex->dh = dh_new_group1(); |
62 | break; | 64 | break; |
63 | case KEX_DH_GRP14_SHA1: | 65 | case KEX_DH_GRP14_SHA1: |
64 | dh = dh_new_group14(); | 66 | kex->dh = dh_new_group14(); |
65 | break; | 67 | break; |
66 | default: | 68 | default: |
67 | fatal("%s: Unexpected KEX type %d", __func__, kex->kex_type); | 69 | r = SSH_ERR_INVALID_ARGUMENT; |
70 | goto out; | ||
68 | } | 71 | } |
69 | dh_gen_key(dh, kex->we_need * 8); | 72 | if (kex->dh == NULL) { |
73 | r = SSH_ERR_ALLOC_FAIL; | ||
74 | goto out; | ||
75 | } | ||
76 | if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) | ||
77 | goto out; | ||
70 | 78 | ||
71 | debug("expecting SSH2_MSG_KEXDH_INIT"); | 79 | debug("expecting SSH2_MSG_KEXDH_INIT"); |
72 | packet_read_expect(SSH2_MSG_KEXDH_INIT); | 80 | ssh_dispatch_set(ssh, SSH2_MSG_KEXDH_INIT, &input_kex_dh_init); |
81 | r = 0; | ||
82 | out: | ||
83 | return r; | ||
84 | } | ||
85 | |||
86 | int | ||
87 | input_kex_dh_init(int type, u_int32_t seq, void *ctxt) | ||
88 | { | ||
89 | struct ssh *ssh = ctxt; | ||
90 | struct kex *kex = ssh->kex; | ||
91 | BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; | ||
92 | struct sshkey *server_host_public, *server_host_private; | ||
93 | u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; | ||
94 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
95 | size_t sbloblen, slen; | ||
96 | size_t klen = 0, hashlen; | ||
97 | int kout, r; | ||
73 | 98 | ||
74 | if (kex->load_host_public_key == NULL || | 99 | if (kex->load_host_public_key == NULL || |
75 | kex->load_host_private_key == NULL) | 100 | kex->load_host_private_key == NULL) { |
76 | fatal("Cannot load hostkey"); | 101 | r = SSH_ERR_INVALID_ARGUMENT; |
77 | server_host_public = kex->load_host_public_key(kex->hostkey_type); | 102 | goto out; |
78 | if (server_host_public == NULL) | 103 | } |
79 | fatal("Unsupported hostkey type %d", kex->hostkey_type); | 104 | if ((server_host_public = kex->load_host_public_key(kex->hostkey_type, |
80 | server_host_private = kex->load_host_private_key(kex->hostkey_type); | 105 | ssh)) == NULL || |
106 | (server_host_private = kex->load_host_private_key(kex->hostkey_type, | ||
107 | ssh)) == NULL) { | ||
108 | r = SSH_ERR_NO_HOSTKEY_LOADED; | ||
109 | goto out; | ||
110 | } | ||
81 | 111 | ||
82 | /* key, cert */ | 112 | /* key, cert */ |
83 | if ((dh_client_pub = BN_new()) == NULL) | 113 | if ((dh_client_pub = BN_new()) == NULL) { |
84 | fatal("dh_client_pub == NULL"); | 114 | r = SSH_ERR_ALLOC_FAIL; |
85 | packet_get_bignum2(dh_client_pub); | 115 | goto out; |
86 | packet_check_eom(); | 116 | } |
117 | if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 || | ||
118 | (r = sshpkt_get_end(ssh)) != 0) | ||
119 | goto out; | ||
87 | 120 | ||
88 | #ifdef DEBUG_KEXDH | 121 | #ifdef DEBUG_KEXDH |
89 | fprintf(stderr, "dh_client_pub= "); | 122 | fprintf(stderr, "dh_client_pub= "); |
@@ -93,71 +126,90 @@ kexdh_server(Kex *kex) | |||
93 | #endif | 126 | #endif |
94 | 127 | ||
95 | #ifdef DEBUG_KEXDH | 128 | #ifdef DEBUG_KEXDH |
96 | DHparams_print_fp(stderr, dh); | 129 | DHparams_print_fp(stderr, kex->dh); |
97 | fprintf(stderr, "pub= "); | 130 | fprintf(stderr, "pub= "); |
98 | BN_print_fp(stderr, dh->pub_key); | 131 | BN_print_fp(stderr, kex->dh->pub_key); |
99 | fprintf(stderr, "\n"); | 132 | fprintf(stderr, "\n"); |
100 | #endif | 133 | #endif |
101 | if (!dh_pub_is_valid(dh, dh_client_pub)) | 134 | if (!dh_pub_is_valid(kex->dh, dh_client_pub)) { |
102 | packet_disconnect("bad client public DH value"); | 135 | sshpkt_disconnect(ssh, "bad client public DH value"); |
136 | r = SSH_ERR_MESSAGE_INCOMPLETE; | ||
137 | goto out; | ||
138 | } | ||
103 | 139 | ||
104 | klen = DH_size(dh); | 140 | klen = DH_size(kex->dh); |
105 | kbuf = xmalloc(klen); | 141 | if ((kbuf = malloc(klen)) == NULL || |
106 | if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) | 142 | (shared_secret = BN_new()) == NULL) { |
107 | fatal("DH_compute_key: failed"); | 143 | r = SSH_ERR_ALLOC_FAIL; |
144 | goto out; | ||
145 | } | ||
146 | if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 || | ||
147 | BN_bin2bn(kbuf, kout, shared_secret) == NULL) { | ||
148 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
149 | goto out; | ||
150 | } | ||
108 | #ifdef DEBUG_KEXDH | 151 | #ifdef DEBUG_KEXDH |
109 | dump_digest("shared secret", kbuf, kout); | 152 | dump_digest("shared secret", kbuf, kout); |
110 | #endif | 153 | #endif |
111 | if ((shared_secret = BN_new()) == NULL) | 154 | if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, |
112 | fatal("kexdh_server: BN_new failed"); | 155 | &sbloblen)) != 0) |
113 | if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) | 156 | goto out; |
114 | fatal("kexdh_server: BN_bin2bn failed"); | ||
115 | explicit_bzero(kbuf, klen); | ||
116 | free(kbuf); | ||
117 | |||
118 | key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); | ||
119 | |||
120 | /* calc H */ | 157 | /* calc H */ |
121 | kex_dh_hash( | 158 | hashlen = sizeof(hash); |
159 | if ((r = kex_dh_hash( | ||
122 | kex->client_version_string, | 160 | kex->client_version_string, |
123 | kex->server_version_string, | 161 | kex->server_version_string, |
124 | buffer_ptr(kex->peer), buffer_len(kex->peer), | 162 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), |
125 | buffer_ptr(kex->my), buffer_len(kex->my), | 163 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), |
126 | server_host_key_blob, sbloblen, | 164 | server_host_key_blob, sbloblen, |
127 | dh_client_pub, | 165 | dh_client_pub, |
128 | dh->pub_key, | 166 | kex->dh->pub_key, |
129 | shared_secret, | 167 | shared_secret, |
130 | &hash, &hashlen | 168 | hash, &hashlen)) != 0) |
131 | ); | 169 | goto out; |
132 | BN_clear_free(dh_client_pub); | ||
133 | 170 | ||
134 | /* save session id := H */ | 171 | /* save session id := H */ |
135 | if (kex->session_id == NULL) { | 172 | if (kex->session_id == NULL) { |
136 | kex->session_id_len = hashlen; | 173 | kex->session_id_len = hashlen; |
137 | kex->session_id = xmalloc(kex->session_id_len); | 174 | kex->session_id = malloc(kex->session_id_len); |
175 | if (kex->session_id == NULL) { | ||
176 | r = SSH_ERR_ALLOC_FAIL; | ||
177 | goto out; | ||
178 | } | ||
138 | memcpy(kex->session_id, hash, kex->session_id_len); | 179 | memcpy(kex->session_id, hash, kex->session_id_len); |
139 | } | 180 | } |
140 | 181 | ||
141 | /* sign H */ | 182 | /* sign H */ |
142 | kex->sign(server_host_private, server_host_public, &signature, &slen, | 183 | if ((r = kex->sign(server_host_private, server_host_public, |
143 | hash, hashlen); | 184 | &signature, &slen, hash, hashlen, ssh->compat)) < 0) |
185 | goto out; | ||
144 | 186 | ||
145 | /* destroy_sensitive_data(); */ | 187 | /* destroy_sensitive_data(); */ |
146 | 188 | ||
147 | /* send server hostkey, DH pubkey 'f' and singed H */ | 189 | /* send server hostkey, DH pubkey 'f' and singed H */ |
148 | packet_start(SSH2_MSG_KEXDH_REPLY); | 190 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEXDH_REPLY)) != 0 || |
149 | packet_put_string(server_host_key_blob, sbloblen); | 191 | (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || |
150 | packet_put_bignum2(dh->pub_key); /* f */ | 192 | (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ |
151 | packet_put_string(signature, slen); | 193 | (r = sshpkt_put_string(ssh, signature, slen)) != 0 || |
152 | packet_send(); | 194 | (r = sshpkt_send(ssh)) != 0) |
153 | 195 | goto out; | |
154 | free(signature); | 196 | |
197 | if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) | ||
198 | r = kex_send_newkeys(ssh); | ||
199 | out: | ||
200 | explicit_bzero(hash, sizeof(hash)); | ||
201 | DH_free(kex->dh); | ||
202 | kex->dh = NULL; | ||
203 | if (dh_client_pub) | ||
204 | BN_clear_free(dh_client_pub); | ||
205 | if (kbuf) { | ||
206 | explicit_bzero(kbuf, klen); | ||
207 | free(kbuf); | ||
208 | } | ||
209 | if (shared_secret) | ||
210 | BN_clear_free(shared_secret); | ||
155 | free(server_host_key_blob); | 211 | free(server_host_key_blob); |
156 | /* have keys, free DH */ | 212 | free(signature); |
157 | DH_free(dh); | 213 | return r; |
158 | |||
159 | kex_derive_keys_bn(kex, hash, hashlen, shared_secret); | ||
160 | BN_clear_free(shared_secret); | ||
161 | kex_finish(kex); | ||
162 | } | 214 | } |
163 | #endif /* WITH_OPENSSL */ | 215 | #endif /* WITH_OPENSSL */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexecdh.c,v 1.5 2014/01/09 23:20:00 djm Exp $ */ | 1 | /* $OpenBSD: kexecdh.c,v 1.6 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2010 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
@@ -38,60 +38,63 @@ | |||
38 | #include <openssl/ec.h> | 38 | #include <openssl/ec.h> |
39 | #include <openssl/ecdh.h> | 39 | #include <openssl/ecdh.h> |
40 | 40 | ||
41 | #include "buffer.h" | ||
42 | #include "ssh2.h" | 41 | #include "ssh2.h" |
43 | #include "key.h" | 42 | #include "sshkey.h" |
44 | #include "cipher.h" | 43 | #include "cipher.h" |
45 | #include "kex.h" | 44 | #include "kex.h" |
46 | #include "log.h" | 45 | #include "sshbuf.h" |
47 | #include "digest.h" | 46 | #include "digest.h" |
47 | #include "ssherr.h" | ||
48 | 48 | ||
49 | void | 49 | int |
50 | kex_ecdh_hash( | 50 | kex_ecdh_hash( |
51 | int hash_alg, | 51 | int hash_alg, |
52 | const EC_GROUP *ec_group, | 52 | const EC_GROUP *ec_group, |
53 | char *client_version_string, | 53 | const char *client_version_string, |
54 | char *server_version_string, | 54 | const char *server_version_string, |
55 | char *ckexinit, int ckexinitlen, | 55 | const u_char *ckexinit, size_t ckexinitlen, |
56 | char *skexinit, int skexinitlen, | 56 | const u_char *skexinit, size_t skexinitlen, |
57 | u_char *serverhostkeyblob, int sbloblen, | 57 | const u_char *serverhostkeyblob, size_t sbloblen, |
58 | const EC_POINT *client_dh_pub, | 58 | const EC_POINT *client_dh_pub, |
59 | const EC_POINT *server_dh_pub, | 59 | const EC_POINT *server_dh_pub, |
60 | const BIGNUM *shared_secret, | 60 | const BIGNUM *shared_secret, |
61 | u_char **hash, u_int *hashlen) | 61 | u_char *hash, size_t *hashlen) |
62 | { | 62 | { |
63 | Buffer b; | 63 | struct sshbuf *b; |
64 | static u_char digest[SSH_DIGEST_MAX_LENGTH]; | 64 | int r; |
65 | |||
66 | buffer_init(&b); | ||
67 | buffer_put_cstring(&b, client_version_string); | ||
68 | buffer_put_cstring(&b, server_version_string); | ||
69 | |||
70 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | ||
71 | buffer_put_int(&b, ckexinitlen+1); | ||
72 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | ||
73 | buffer_append(&b, ckexinit, ckexinitlen); | ||
74 | buffer_put_int(&b, skexinitlen+1); | ||
75 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | ||
76 | buffer_append(&b, skexinit, skexinitlen); | ||
77 | |||
78 | buffer_put_string(&b, serverhostkeyblob, sbloblen); | ||
79 | buffer_put_ecpoint(&b, ec_group, client_dh_pub); | ||
80 | buffer_put_ecpoint(&b, ec_group, server_dh_pub); | ||
81 | buffer_put_bignum2(&b, shared_secret); | ||
82 | 65 | ||
66 | if (*hashlen < ssh_digest_bytes(hash_alg)) | ||
67 | return SSH_ERR_INVALID_ARGUMENT; | ||
68 | if ((b = sshbuf_new()) == NULL) | ||
69 | return SSH_ERR_ALLOC_FAIL; | ||
70 | if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 || | ||
71 | (r = sshbuf_put_cstring(b, server_version_string)) != 0 || | ||
72 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | ||
73 | (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 || | ||
74 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || | ||
75 | (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 || | ||
76 | (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 || | ||
77 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || | ||
78 | (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || | ||
79 | (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || | ||
80 | (r = sshbuf_put_ec(b, client_dh_pub, ec_group)) != 0 || | ||
81 | (r = sshbuf_put_ec(b, server_dh_pub, ec_group)) != 0 || | ||
82 | (r = sshbuf_put_bignum2(b, shared_secret)) != 0) { | ||
83 | sshbuf_free(b); | ||
84 | return r; | ||
85 | } | ||
83 | #ifdef DEBUG_KEX | 86 | #ifdef DEBUG_KEX |
84 | buffer_dump(&b); | 87 | sshbuf_dump(b, stderr); |
85 | #endif | 88 | #endif |
86 | if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0) | 89 | if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { |
87 | fatal("%s: ssh_digest_buffer failed", __func__); | 90 | sshbuf_free(b); |
88 | 91 | return SSH_ERR_LIBCRYPTO_ERROR; | |
89 | buffer_free(&b); | 92 | } |
90 | 93 | sshbuf_free(b); | |
94 | *hashlen = ssh_digest_bytes(hash_alg); | ||
91 | #ifdef DEBUG_KEX | 95 | #ifdef DEBUG_KEX |
92 | dump_digest("hash", digest, ssh_digest_bytes(hash_alg)); | 96 | dump_digest("hash", hash, *hashlen); |
93 | #endif | 97 | #endif |
94 | *hash = digest; | 98 | return 0; |
95 | *hashlen = ssh_digest_bytes(hash_alg); | ||
96 | } | 99 | } |
97 | #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ | 100 | #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ |
diff --git a/kexecdhc.c b/kexecdhc.c index df811c1c8..3f362c5b1 100644 --- a/kexecdhc.c +++ b/kexecdhc.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexecdhc.c,v 1.8 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: kexecdhc.c,v 1.9 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2010 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
@@ -34,126 +34,193 @@ | |||
34 | #include <string.h> | 34 | #include <string.h> |
35 | #include <signal.h> | 35 | #include <signal.h> |
36 | 36 | ||
37 | #include "xmalloc.h" | 37 | #include <openssl/ecdh.h> |
38 | #include "buffer.h" | 38 | |
39 | #include "key.h" | 39 | #include "sshkey.h" |
40 | #include "cipher.h" | 40 | #include "cipher.h" |
41 | #include "digest.h" | ||
41 | #include "kex.h" | 42 | #include "kex.h" |
42 | #include "log.h" | 43 | #include "log.h" |
43 | #include "packet.h" | 44 | #include "packet.h" |
44 | #include "dh.h" | 45 | #include "dh.h" |
45 | #include "ssh2.h" | 46 | #include "ssh2.h" |
47 | #include "dispatch.h" | ||
48 | #include "compat.h" | ||
49 | #include "ssherr.h" | ||
50 | #include "sshbuf.h" | ||
46 | 51 | ||
47 | #include <openssl/ecdh.h> | 52 | static int input_kex_ecdh_reply(int, u_int32_t, void *); |
48 | 53 | ||
49 | void | 54 | int |
50 | kexecdh_client(Kex *kex) | 55 | kexecdh_client(struct ssh *ssh) |
51 | { | 56 | { |
52 | EC_KEY *client_key; | 57 | struct kex *kex = ssh->kex; |
53 | EC_POINT *server_public; | 58 | EC_KEY *client_key = NULL; |
54 | const EC_GROUP *group; | 59 | const EC_GROUP *group; |
55 | BIGNUM *shared_secret; | 60 | const EC_POINT *public_key; |
56 | Key *server_host_key; | 61 | int r; |
57 | u_char *server_host_key_blob = NULL, *signature = NULL; | ||
58 | u_char *kbuf, *hash; | ||
59 | u_int klen, slen, sbloblen, hashlen; | ||
60 | 62 | ||
61 | if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) | 63 | if ((client_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { |
62 | fatal("%s: EC_KEY_new_by_curve_name failed", __func__); | 64 | r = SSH_ERR_ALLOC_FAIL; |
63 | if (EC_KEY_generate_key(client_key) != 1) | 65 | goto out; |
64 | fatal("%s: EC_KEY_generate_key failed", __func__); | 66 | } |
67 | if (EC_KEY_generate_key(client_key) != 1) { | ||
68 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
69 | goto out; | ||
70 | } | ||
65 | group = EC_KEY_get0_group(client_key); | 71 | group = EC_KEY_get0_group(client_key); |
72 | public_key = EC_KEY_get0_public_key(client_key); | ||
66 | 73 | ||
67 | packet_start(SSH2_MSG_KEX_ECDH_INIT); | 74 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_INIT)) != 0 || |
68 | packet_put_ecpoint(group, EC_KEY_get0_public_key(client_key)); | 75 | (r = sshpkt_put_ec(ssh, public_key, group)) != 0 || |
69 | packet_send(); | 76 | (r = sshpkt_send(ssh)) != 0) |
77 | goto out; | ||
70 | debug("sending SSH2_MSG_KEX_ECDH_INIT"); | 78 | debug("sending SSH2_MSG_KEX_ECDH_INIT"); |
71 | 79 | ||
72 | #ifdef DEBUG_KEXECDH | 80 | #ifdef DEBUG_KEXECDH |
73 | fputs("client private key:\n", stderr); | 81 | fputs("client private key:\n", stderr); |
74 | key_dump_ec_key(client_key); | 82 | sshkey_dump_ec_key(client_key); |
75 | #endif | 83 | #endif |
84 | kex->ec_client_key = client_key; | ||
85 | kex->ec_group = group; | ||
86 | client_key = NULL; /* owned by the kex */ | ||
76 | 87 | ||
77 | debug("expecting SSH2_MSG_KEX_ECDH_REPLY"); | 88 | debug("expecting SSH2_MSG_KEX_ECDH_REPLY"); |
78 | packet_read_expect(SSH2_MSG_KEX_ECDH_REPLY); | 89 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_REPLY, &input_kex_ecdh_reply); |
90 | r = 0; | ||
91 | out: | ||
92 | if (client_key) | ||
93 | EC_KEY_free(client_key); | ||
94 | return r; | ||
95 | } | ||
96 | |||
97 | static int | ||
98 | input_kex_ecdh_reply(int type, u_int32_t seq, void *ctxt) | ||
99 | { | ||
100 | struct ssh *ssh = ctxt; | ||
101 | struct kex *kex = ssh->kex; | ||
102 | const EC_GROUP *group; | ||
103 | EC_POINT *server_public = NULL; | ||
104 | EC_KEY *client_key; | ||
105 | BIGNUM *shared_secret = NULL; | ||
106 | struct sshkey *server_host_key = NULL; | ||
107 | u_char *server_host_key_blob = NULL, *signature = NULL; | ||
108 | u_char *kbuf = NULL; | ||
109 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
110 | size_t slen, sbloblen; | ||
111 | size_t klen = 0, hashlen; | ||
112 | int r; | ||
113 | |||
114 | if (kex->verify_host_key == NULL) { | ||
115 | r = SSH_ERR_INVALID_ARGUMENT; | ||
116 | goto out; | ||
117 | } | ||
118 | group = kex->ec_group; | ||
119 | client_key = kex->ec_client_key; | ||
79 | 120 | ||
80 | /* hostkey */ | 121 | /* hostkey */ |
81 | server_host_key_blob = packet_get_string(&sbloblen); | 122 | if ((r = sshpkt_get_string(ssh, &server_host_key_blob, |
82 | server_host_key = key_from_blob(server_host_key_blob, sbloblen); | 123 | &sbloblen)) != 0 || |
83 | if (server_host_key == NULL) | 124 | (r = sshkey_from_blob(server_host_key_blob, sbloblen, |
84 | fatal("cannot decode server_host_key_blob"); | 125 | &server_host_key)) != 0) |
85 | if (server_host_key->type != kex->hostkey_type) | 126 | goto out; |
86 | fatal("type mismatch for decoded server_host_key_blob"); | 127 | if (server_host_key->type != kex->hostkey_type) { |
87 | if (kex->verify_host_key == NULL) | 128 | r = SSH_ERR_KEY_TYPE_MISMATCH; |
88 | fatal("cannot verify server_host_key"); | 129 | goto out; |
89 | if (kex->verify_host_key(server_host_key) == -1) | 130 | } |
90 | fatal("server_host_key verification failed"); | 131 | if (kex->verify_host_key(server_host_key, ssh) == -1) { |
132 | r = SSH_ERR_SIGNATURE_INVALID; | ||
133 | goto out; | ||
134 | } | ||
91 | 135 | ||
92 | /* Q_S, server public key */ | 136 | /* Q_S, server public key */ |
93 | if ((server_public = EC_POINT_new(group)) == NULL) | 137 | /* signed H */ |
94 | fatal("%s: EC_POINT_new failed", __func__); | 138 | if ((server_public = EC_POINT_new(group)) == NULL) { |
95 | packet_get_ecpoint(group, server_public); | 139 | r = SSH_ERR_ALLOC_FAIL; |
96 | 140 | goto out; | |
97 | if (key_ec_validate_public(group, server_public) != 0) | 141 | } |
98 | fatal("%s: invalid server public key", __func__); | 142 | if ((r = sshpkt_get_ec(ssh, server_public, group)) != 0 || |
143 | (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || | ||
144 | (r = sshpkt_get_end(ssh)) != 0) | ||
145 | goto out; | ||
99 | 146 | ||
100 | #ifdef DEBUG_KEXECDH | 147 | #ifdef DEBUG_KEXECDH |
101 | fputs("server public key:\n", stderr); | 148 | fputs("server public key:\n", stderr); |
102 | key_dump_ec_point(group, server_public); | 149 | sshkey_dump_ec_point(group, server_public); |
103 | #endif | 150 | #endif |
104 | 151 | if (sshkey_ec_validate_public(group, server_public) != 0) { | |
105 | /* signed H */ | 152 | sshpkt_disconnect(ssh, "invalid server public key"); |
106 | signature = packet_get_string(&slen); | 153 | r = SSH_ERR_MESSAGE_INCOMPLETE; |
107 | packet_check_eom(); | 154 | goto out; |
155 | } | ||
108 | 156 | ||
109 | klen = (EC_GROUP_get_degree(group) + 7) / 8; | 157 | klen = (EC_GROUP_get_degree(group) + 7) / 8; |
110 | kbuf = xmalloc(klen); | 158 | if ((kbuf = malloc(klen)) == NULL || |
159 | (shared_secret = BN_new()) == NULL) { | ||
160 | r = SSH_ERR_ALLOC_FAIL; | ||
161 | goto out; | ||
162 | } | ||
111 | if (ECDH_compute_key(kbuf, klen, server_public, | 163 | if (ECDH_compute_key(kbuf, klen, server_public, |
112 | client_key, NULL) != (int)klen) | 164 | client_key, NULL) != (int)klen || |
113 | fatal("%s: ECDH_compute_key failed", __func__); | 165 | BN_bin2bn(kbuf, klen, shared_secret) == NULL) { |
166 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
167 | goto out; | ||
168 | } | ||
114 | 169 | ||
115 | #ifdef DEBUG_KEXECDH | 170 | #ifdef DEBUG_KEXECDH |
116 | dump_digest("shared secret", kbuf, klen); | 171 | dump_digest("shared secret", kbuf, klen); |
117 | #endif | 172 | #endif |
118 | if ((shared_secret = BN_new()) == NULL) | ||
119 | fatal("%s: BN_new failed", __func__); | ||
120 | if (BN_bin2bn(kbuf, klen, shared_secret) == NULL) | ||
121 | fatal("%s: BN_bin2bn failed", __func__); | ||
122 | explicit_bzero(kbuf, klen); | ||
123 | free(kbuf); | ||
124 | |||
125 | /* calc and verify H */ | 173 | /* calc and verify H */ |
126 | kex_ecdh_hash( | 174 | hashlen = sizeof(hash); |
175 | if ((r = kex_ecdh_hash( | ||
127 | kex->hash_alg, | 176 | kex->hash_alg, |
128 | group, | 177 | group, |
129 | kex->client_version_string, | 178 | kex->client_version_string, |
130 | kex->server_version_string, | 179 | kex->server_version_string, |
131 | buffer_ptr(kex->my), buffer_len(kex->my), | 180 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), |
132 | buffer_ptr(kex->peer), buffer_len(kex->peer), | 181 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), |
133 | server_host_key_blob, sbloblen, | 182 | server_host_key_blob, sbloblen, |
134 | EC_KEY_get0_public_key(client_key), | 183 | EC_KEY_get0_public_key(client_key), |
135 | server_public, | 184 | server_public, |
136 | shared_secret, | 185 | shared_secret, |
137 | &hash, &hashlen | 186 | hash, &hashlen)) != 0) |
138 | ); | 187 | goto out; |
139 | free(server_host_key_blob); | ||
140 | EC_POINT_clear_free(server_public); | ||
141 | EC_KEY_free(client_key); | ||
142 | 188 | ||
143 | if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) | 189 | if ((r = sshkey_verify(server_host_key, signature, slen, hash, |
144 | fatal("key_verify failed for server_host_key"); | 190 | hashlen, ssh->compat)) != 0) |
145 | key_free(server_host_key); | 191 | goto out; |
146 | free(signature); | ||
147 | 192 | ||
148 | /* save session id */ | 193 | /* save session id */ |
149 | if (kex->session_id == NULL) { | 194 | if (kex->session_id == NULL) { |
150 | kex->session_id_len = hashlen; | 195 | kex->session_id_len = hashlen; |
151 | kex->session_id = xmalloc(kex->session_id_len); | 196 | kex->session_id = malloc(kex->session_id_len); |
197 | if (kex->session_id == NULL) { | ||
198 | r = SSH_ERR_ALLOC_FAIL; | ||
199 | goto out; | ||
200 | } | ||
152 | memcpy(kex->session_id, hash, kex->session_id_len); | 201 | memcpy(kex->session_id, hash, kex->session_id_len); |
153 | } | 202 | } |
154 | 203 | ||
155 | kex_derive_keys_bn(kex, hash, hashlen, shared_secret); | 204 | if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) |
156 | BN_clear_free(shared_secret); | 205 | r = kex_send_newkeys(ssh); |
157 | kex_finish(kex); | 206 | out: |
207 | explicit_bzero(hash, sizeof(hash)); | ||
208 | if (kex->ec_client_key) { | ||
209 | EC_KEY_free(kex->ec_client_key); | ||
210 | kex->ec_client_key = NULL; | ||
211 | } | ||
212 | if (server_public) | ||
213 | EC_POINT_clear_free(server_public); | ||
214 | if (kbuf) { | ||
215 | explicit_bzero(kbuf, klen); | ||
216 | free(kbuf); | ||
217 | } | ||
218 | if (shared_secret) | ||
219 | BN_clear_free(shared_secret); | ||
220 | sshkey_free(server_host_key); | ||
221 | free(server_host_key_blob); | ||
222 | free(signature); | ||
223 | return r; | ||
158 | } | 224 | } |
159 | #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ | 225 | #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ |
226 | |||
diff --git a/kexecdhs.c b/kexecdhs.c index 6bfad04cf..6b8d95d9c 100644 --- a/kexecdhs.c +++ b/kexecdhs.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexecdhs.c,v 1.11 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: kexecdhs.c,v 1.12 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2010 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2010 Damien Miller. All rights reserved. |
@@ -32,124 +32,176 @@ | |||
32 | #include <string.h> | 32 | #include <string.h> |
33 | #include <signal.h> | 33 | #include <signal.h> |
34 | 34 | ||
35 | #include "xmalloc.h" | 35 | #include <openssl/ecdh.h> |
36 | #include "buffer.h" | 36 | |
37 | #include "key.h" | 37 | #include "sshkey.h" |
38 | #include "cipher.h" | 38 | #include "cipher.h" |
39 | #include "digest.h" | ||
39 | #include "kex.h" | 40 | #include "kex.h" |
40 | #include "log.h" | 41 | #include "log.h" |
41 | #include "packet.h" | 42 | #include "packet.h" |
42 | #include "ssh2.h" | 43 | #include "ssh2.h" |
43 | 44 | ||
44 | #include <openssl/ecdh.h> | 45 | #include "dispatch.h" |
46 | #include "compat.h" | ||
47 | #include "ssherr.h" | ||
48 | #include "sshbuf.h" | ||
49 | |||
50 | static int input_kex_ecdh_init(int, u_int32_t, void *); | ||
51 | |||
52 | int | ||
53 | kexecdh_server(struct ssh *ssh) | ||
54 | { | ||
55 | debug("expecting SSH2_MSG_KEX_ECDH_INIT"); | ||
56 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_ECDH_INIT, &input_kex_ecdh_init); | ||
57 | return 0; | ||
58 | } | ||
45 | 59 | ||
46 | void | 60 | static int |
47 | kexecdh_server(Kex *kex) | 61 | input_kex_ecdh_init(int type, u_int32_t seq, void *ctxt) |
48 | { | 62 | { |
63 | struct ssh *ssh = ctxt; | ||
64 | struct kex *kex = ssh->kex; | ||
49 | EC_POINT *client_public; | 65 | EC_POINT *client_public; |
50 | EC_KEY *server_key; | 66 | EC_KEY *server_key = NULL; |
51 | const EC_GROUP *group; | 67 | const EC_GROUP *group; |
52 | BIGNUM *shared_secret; | 68 | const EC_POINT *public_key; |
53 | Key *server_host_private, *server_host_public; | 69 | BIGNUM *shared_secret = NULL; |
70 | struct sshkey *server_host_private, *server_host_public; | ||
54 | u_char *server_host_key_blob = NULL, *signature = NULL; | 71 | u_char *server_host_key_blob = NULL, *signature = NULL; |
55 | u_char *kbuf, *hash; | 72 | u_char *kbuf = NULL; |
56 | u_int klen, slen, sbloblen, hashlen; | 73 | u_char hash[SSH_DIGEST_MAX_LENGTH]; |
57 | 74 | size_t slen, sbloblen; | |
58 | if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) | 75 | size_t klen = 0, hashlen; |
59 | fatal("%s: EC_KEY_new_by_curve_name failed", __func__); | 76 | int r; |
60 | if (EC_KEY_generate_key(server_key) != 1) | 77 | |
61 | fatal("%s: EC_KEY_generate_key failed", __func__); | 78 | if ((server_key = EC_KEY_new_by_curve_name(kex->ec_nid)) == NULL) { |
79 | r = SSH_ERR_ALLOC_FAIL; | ||
80 | goto out; | ||
81 | } | ||
82 | if (EC_KEY_generate_key(server_key) != 1) { | ||
83 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
84 | goto out; | ||
85 | } | ||
62 | group = EC_KEY_get0_group(server_key); | 86 | group = EC_KEY_get0_group(server_key); |
63 | 87 | ||
64 | #ifdef DEBUG_KEXECDH | 88 | #ifdef DEBUG_KEXECDH |
65 | fputs("server private key:\n", stderr); | 89 | fputs("server private key:\n", stderr); |
66 | key_dump_ec_key(server_key); | 90 | sshkey_dump_ec_key(server_key); |
67 | #endif | 91 | #endif |
68 | 92 | ||
69 | if (kex->load_host_public_key == NULL || | 93 | if (kex->load_host_public_key == NULL || |
70 | kex->load_host_private_key == NULL) | 94 | kex->load_host_private_key == NULL) { |
71 | fatal("Cannot load hostkey"); | 95 | r = SSH_ERR_INVALID_ARGUMENT; |
72 | server_host_public = kex->load_host_public_key(kex->hostkey_type); | 96 | goto out; |
73 | if (server_host_public == NULL) | 97 | } |
74 | fatal("Unsupported hostkey type %d", kex->hostkey_type); | 98 | if ((server_host_public = kex->load_host_public_key(kex->hostkey_type, |
75 | server_host_private = kex->load_host_private_key(kex->hostkey_type); | 99 | ssh)) == NULL || |
76 | 100 | (server_host_private = kex->load_host_private_key(kex->hostkey_type, | |
77 | debug("expecting SSH2_MSG_KEX_ECDH_INIT"); | 101 | ssh)) == NULL) { |
78 | packet_read_expect(SSH2_MSG_KEX_ECDH_INIT); | 102 | r = SSH_ERR_NO_HOSTKEY_LOADED; |
79 | if ((client_public = EC_POINT_new(group)) == NULL) | 103 | goto out; |
80 | fatal("%s: EC_POINT_new failed", __func__); | 104 | } |
81 | packet_get_ecpoint(group, client_public); | 105 | if ((client_public = EC_POINT_new(group)) == NULL) { |
82 | packet_check_eom(); | 106 | r = SSH_ERR_ALLOC_FAIL; |
83 | 107 | goto out; | |
84 | if (key_ec_validate_public(group, client_public) != 0) | 108 | } |
85 | fatal("%s: invalid client public key", __func__); | 109 | if ((r = sshpkt_get_ec(ssh, client_public, group)) != 0 || |
110 | (r = sshpkt_get_end(ssh)) != 0) | ||
111 | goto out; | ||
86 | 112 | ||
87 | #ifdef DEBUG_KEXECDH | 113 | #ifdef DEBUG_KEXECDH |
88 | fputs("client public key:\n", stderr); | 114 | fputs("client public key:\n", stderr); |
89 | key_dump_ec_point(group, client_public); | 115 | sshkey_dump_ec_point(group, client_public); |
90 | #endif | 116 | #endif |
117 | if (sshkey_ec_validate_public(group, client_public) != 0) { | ||
118 | sshpkt_disconnect(ssh, "invalid client public key"); | ||
119 | r = SSH_ERR_MESSAGE_INCOMPLETE; | ||
120 | goto out; | ||
121 | } | ||
91 | 122 | ||
92 | /* Calculate shared_secret */ | 123 | /* Calculate shared_secret */ |
93 | klen = (EC_GROUP_get_degree(group) + 7) / 8; | 124 | klen = (EC_GROUP_get_degree(group) + 7) / 8; |
94 | kbuf = xmalloc(klen); | 125 | if ((kbuf = malloc(klen)) == NULL || |
126 | (shared_secret = BN_new()) == NULL) { | ||
127 | r = SSH_ERR_ALLOC_FAIL; | ||
128 | goto out; | ||
129 | } | ||
95 | if (ECDH_compute_key(kbuf, klen, client_public, | 130 | if (ECDH_compute_key(kbuf, klen, client_public, |
96 | server_key, NULL) != (int)klen) | 131 | server_key, NULL) != (int)klen || |
97 | fatal("%s: ECDH_compute_key failed", __func__); | 132 | BN_bin2bn(kbuf, klen, shared_secret) == NULL) { |
133 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
134 | goto out; | ||
135 | } | ||
98 | 136 | ||
99 | #ifdef DEBUG_KEXDH | 137 | #ifdef DEBUG_KEXECDH |
100 | dump_digest("shared secret", kbuf, klen); | 138 | dump_digest("shared secret", kbuf, klen); |
101 | #endif | 139 | #endif |
102 | if ((shared_secret = BN_new()) == NULL) | ||
103 | fatal("%s: BN_new failed", __func__); | ||
104 | if (BN_bin2bn(kbuf, klen, shared_secret) == NULL) | ||
105 | fatal("%s: BN_bin2bn failed", __func__); | ||
106 | explicit_bzero(kbuf, klen); | ||
107 | free(kbuf); | ||
108 | |||
109 | /* calc H */ | 140 | /* calc H */ |
110 | key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); | 141 | if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, |
111 | kex_ecdh_hash( | 142 | &sbloblen)) != 0) |
143 | goto out; | ||
144 | hashlen = sizeof(hash); | ||
145 | if ((r = kex_ecdh_hash( | ||
112 | kex->hash_alg, | 146 | kex->hash_alg, |
113 | group, | 147 | group, |
114 | kex->client_version_string, | 148 | kex->client_version_string, |
115 | kex->server_version_string, | 149 | kex->server_version_string, |
116 | buffer_ptr(kex->peer), buffer_len(kex->peer), | 150 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), |
117 | buffer_ptr(kex->my), buffer_len(kex->my), | 151 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), |
118 | server_host_key_blob, sbloblen, | 152 | server_host_key_blob, sbloblen, |
119 | client_public, | 153 | client_public, |
120 | EC_KEY_get0_public_key(server_key), | 154 | EC_KEY_get0_public_key(server_key), |
121 | shared_secret, | 155 | shared_secret, |
122 | &hash, &hashlen | 156 | hash, &hashlen)) != 0) |
123 | ); | 157 | goto out; |
124 | EC_POINT_clear_free(client_public); | ||
125 | 158 | ||
126 | /* save session id := H */ | 159 | /* save session id := H */ |
127 | if (kex->session_id == NULL) { | 160 | if (kex->session_id == NULL) { |
128 | kex->session_id_len = hashlen; | 161 | kex->session_id_len = hashlen; |
129 | kex->session_id = xmalloc(kex->session_id_len); | 162 | kex->session_id = malloc(kex->session_id_len); |
163 | if (kex->session_id == NULL) { | ||
164 | r = SSH_ERR_ALLOC_FAIL; | ||
165 | goto out; | ||
166 | } | ||
130 | memcpy(kex->session_id, hash, kex->session_id_len); | 167 | memcpy(kex->session_id, hash, kex->session_id_len); |
131 | } | 168 | } |
132 | 169 | ||
133 | /* sign H */ | 170 | /* sign H */ |
134 | kex->sign(server_host_private, server_host_public, &signature, &slen, | 171 | if ((r = kex->sign(server_host_private, server_host_public, |
135 | hash, hashlen); | 172 | &signature, &slen, hash, hashlen, ssh->compat)) < 0) |
173 | goto out; | ||
136 | 174 | ||
137 | /* destroy_sensitive_data(); */ | 175 | /* destroy_sensitive_data(); */ |
138 | 176 | ||
177 | public_key = EC_KEY_get0_public_key(server_key); | ||
139 | /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ | 178 | /* send server hostkey, ECDH pubkey 'Q_S' and signed H */ |
140 | packet_start(SSH2_MSG_KEX_ECDH_REPLY); | 179 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_ECDH_REPLY)) != 0 || |
141 | packet_put_string(server_host_key_blob, sbloblen); | 180 | (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || |
142 | packet_put_ecpoint(group, EC_KEY_get0_public_key(server_key)); | 181 | (r = sshpkt_put_ec(ssh, public_key, group)) != 0 || |
143 | packet_put_string(signature, slen); | 182 | (r = sshpkt_put_string(ssh, signature, slen)) != 0 || |
144 | packet_send(); | 183 | (r = sshpkt_send(ssh)) != 0) |
145 | 184 | goto out; | |
146 | free(signature); | 185 | |
186 | if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) | ||
187 | r = kex_send_newkeys(ssh); | ||
188 | out: | ||
189 | explicit_bzero(hash, sizeof(hash)); | ||
190 | if (kex->ec_client_key) { | ||
191 | EC_KEY_free(kex->ec_client_key); | ||
192 | kex->ec_client_key = NULL; | ||
193 | } | ||
194 | if (server_key) | ||
195 | EC_KEY_free(server_key); | ||
196 | if (kbuf) { | ||
197 | explicit_bzero(kbuf, klen); | ||
198 | free(kbuf); | ||
199 | } | ||
200 | if (shared_secret) | ||
201 | BN_clear_free(shared_secret); | ||
147 | free(server_host_key_blob); | 202 | free(server_host_key_blob); |
148 | /* have keys, free server key */ | 203 | free(signature); |
149 | EC_KEY_free(server_key); | 204 | return r; |
150 | |||
151 | kex_derive_keys_bn(kex, hash, hashlen, shared_secret); | ||
152 | BN_clear_free(shared_secret); | ||
153 | kex_finish(kex); | ||
154 | } | 205 | } |
155 | #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ | 206 | #endif /* defined(WITH_OPENSSL) && defined(OPENSSL_HAS_ECC) */ |
207 | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexgex.c,v 1.28 2014/01/09 23:20:00 djm Exp $ */ | 1 | /* $OpenBSD: kexgex.c,v 1.29 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Niels Provos. All rights reserved. | 3 | * Copyright (c) 2000 Niels Provos. All rights reserved. |
4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
@@ -33,69 +33,70 @@ | |||
33 | #include <openssl/evp.h> | 33 | #include <openssl/evp.h> |
34 | #include <signal.h> | 34 | #include <signal.h> |
35 | 35 | ||
36 | #include "buffer.h" | 36 | #include "sshkey.h" |
37 | #include "key.h" | ||
38 | #include "cipher.h" | 37 | #include "cipher.h" |
39 | #include "kex.h" | 38 | #include "kex.h" |
40 | #include "ssh2.h" | 39 | #include "ssh2.h" |
40 | #include "ssherr.h" | ||
41 | #include "sshbuf.h" | ||
41 | #include "digest.h" | 42 | #include "digest.h" |
42 | #include "log.h" | ||
43 | 43 | ||
44 | void | 44 | int |
45 | kexgex_hash( | 45 | kexgex_hash( |
46 | int hash_alg, | 46 | int hash_alg, |
47 | char *client_version_string, | 47 | const char *client_version_string, |
48 | char *server_version_string, | 48 | const char *server_version_string, |
49 | char *ckexinit, int ckexinitlen, | 49 | const u_char *ckexinit, size_t ckexinitlen, |
50 | char *skexinit, int skexinitlen, | 50 | const u_char *skexinit, size_t skexinitlen, |
51 | u_char *serverhostkeyblob, int sbloblen, | 51 | const u_char *serverhostkeyblob, size_t sbloblen, |
52 | int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen, | 52 | int min, int wantbits, int max, |
53 | BIGNUM *client_dh_pub, | 53 | const BIGNUM *prime, |
54 | BIGNUM *server_dh_pub, | 54 | const BIGNUM *gen, |
55 | BIGNUM *shared_secret, | 55 | const BIGNUM *client_dh_pub, |
56 | u_char **hash, u_int *hashlen) | 56 | const BIGNUM *server_dh_pub, |
57 | const BIGNUM *shared_secret, | ||
58 | u_char *hash, size_t *hashlen) | ||
57 | { | 59 | { |
58 | Buffer b; | 60 | struct sshbuf *b; |
59 | static u_char digest[SSH_DIGEST_MAX_LENGTH]; | 61 | int r; |
60 | 62 | ||
61 | buffer_init(&b); | 63 | if (*hashlen < ssh_digest_bytes(SSH_DIGEST_SHA1)) |
62 | buffer_put_cstring(&b, client_version_string); | 64 | return SSH_ERR_INVALID_ARGUMENT; |
63 | buffer_put_cstring(&b, server_version_string); | 65 | if ((b = sshbuf_new()) == NULL) |
64 | 66 | return SSH_ERR_ALLOC_FAIL; | |
65 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | 67 | if ((r = sshbuf_put_cstring(b, client_version_string)) != 0 || |
66 | buffer_put_int(&b, ckexinitlen+1); | 68 | (r = sshbuf_put_cstring(b, server_version_string)) != 0 || |
67 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | 69 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ |
68 | buffer_append(&b, ckexinit, ckexinitlen); | 70 | (r = sshbuf_put_u32(b, ckexinitlen+1)) != 0 || |
69 | buffer_put_int(&b, skexinitlen+1); | 71 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || |
70 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | 72 | (r = sshbuf_put(b, ckexinit, ckexinitlen)) != 0 || |
71 | buffer_append(&b, skexinit, skexinitlen); | 73 | (r = sshbuf_put_u32(b, skexinitlen+1)) != 0 || |
72 | 74 | (r = sshbuf_put_u8(b, SSH2_MSG_KEXINIT)) != 0 || | |
73 | buffer_put_string(&b, serverhostkeyblob, sbloblen); | 75 | (r = sshbuf_put(b, skexinit, skexinitlen)) != 0 || |
74 | if (min == -1 || max == -1) | 76 | (r = sshbuf_put_string(b, serverhostkeyblob, sbloblen)) != 0 || |
75 | buffer_put_int(&b, wantbits); | 77 | (min != -1 && (r = sshbuf_put_u32(b, min)) != 0) || |
76 | else { | 78 | (r = sshbuf_put_u32(b, wantbits)) != 0 || |
77 | buffer_put_int(&b, min); | 79 | (max != -1 && (r = sshbuf_put_u32(b, max)) != 0) || |
78 | buffer_put_int(&b, wantbits); | 80 | (r = sshbuf_put_bignum2(b, prime)) != 0 || |
79 | buffer_put_int(&b, max); | 81 | (r = sshbuf_put_bignum2(b, gen)) != 0 || |
82 | (r = sshbuf_put_bignum2(b, client_dh_pub)) != 0 || | ||
83 | (r = sshbuf_put_bignum2(b, server_dh_pub)) != 0 || | ||
84 | (r = sshbuf_put_bignum2(b, shared_secret)) != 0) { | ||
85 | sshbuf_free(b); | ||
86 | return r; | ||
80 | } | 87 | } |
81 | buffer_put_bignum2(&b, prime); | ||
82 | buffer_put_bignum2(&b, gen); | ||
83 | buffer_put_bignum2(&b, client_dh_pub); | ||
84 | buffer_put_bignum2(&b, server_dh_pub); | ||
85 | buffer_put_bignum2(&b, shared_secret); | ||
86 | |||
87 | #ifdef DEBUG_KEXDH | 88 | #ifdef DEBUG_KEXDH |
88 | buffer_dump(&b); | 89 | sshbuf_dump(b, stderr); |
89 | #endif | 90 | #endif |
90 | if (ssh_digest_buffer(hash_alg, &b, digest, sizeof(digest)) != 0) | 91 | if (ssh_digest_buffer(hash_alg, b, hash, *hashlen) != 0) { |
91 | fatal("%s: ssh_digest_buffer failed", __func__); | 92 | sshbuf_free(b); |
92 | 93 | return SSH_ERR_LIBCRYPTO_ERROR; | |
93 | buffer_free(&b); | 94 | } |
94 | 95 | sshbuf_free(b); | |
95 | #ifdef DEBUG_KEX | ||
96 | dump_digest("hash", digest, ssh_digest_bytes(hash_alg)); | ||
97 | #endif | ||
98 | *hash = digest; | ||
99 | *hashlen = ssh_digest_bytes(hash_alg); | 96 | *hashlen = ssh_digest_bytes(hash_alg); |
97 | #ifdef DEBUG_KEXDH | ||
98 | dump_digest("hash", hash, *hashlen); | ||
99 | #endif | ||
100 | return 0; | ||
100 | } | 101 | } |
101 | #endif /* WITH_OPENSSL */ | 102 | #endif /* WITH_OPENSSL */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexgexc.c,v 1.18 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: kexgexc.c,v 1.19 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Niels Provos. All rights reserved. | 3 | * Copyright (c) 2000 Niels Provos. All rights reserved. |
4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
@@ -37,174 +37,237 @@ | |||
37 | #include <string.h> | 37 | #include <string.h> |
38 | #include <signal.h> | 38 | #include <signal.h> |
39 | 39 | ||
40 | #include "xmalloc.h" | 40 | #include "sshkey.h" |
41 | #include "buffer.h" | ||
42 | #include "key.h" | ||
43 | #include "cipher.h" | 41 | #include "cipher.h" |
42 | #include "digest.h" | ||
44 | #include "kex.h" | 43 | #include "kex.h" |
45 | #include "log.h" | 44 | #include "log.h" |
46 | #include "packet.h" | 45 | #include "packet.h" |
47 | #include "dh.h" | 46 | #include "dh.h" |
48 | #include "ssh2.h" | 47 | #include "ssh2.h" |
49 | #include "compat.h" | 48 | #include "compat.h" |
49 | #include "dispatch.h" | ||
50 | #include "ssherr.h" | ||
51 | #include "sshbuf.h" | ||
50 | 52 | ||
51 | void | 53 | static int input_kex_dh_gex_group(int, u_int32_t, void *); |
52 | kexgex_client(Kex *kex) | 54 | static int input_kex_dh_gex_reply(int, u_int32_t, void *); |
55 | |||
56 | int | ||
57 | kexgex_client(struct ssh *ssh) | ||
53 | { | 58 | { |
54 | BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; | 59 | struct kex *kex = ssh->kex; |
55 | BIGNUM *p = NULL, *g = NULL; | 60 | int r; |
56 | Key *server_host_key; | 61 | u_int nbits; |
57 | u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; | ||
58 | u_int klen, slen, sbloblen, hashlen; | ||
59 | int kout; | ||
60 | int min, max, nbits; | ||
61 | DH *dh; | ||
62 | 62 | ||
63 | nbits = dh_estimate(kex->dh_need * 8); | 63 | nbits = dh_estimate(kex->dh_need * 8); |
64 | 64 | ||
65 | if (datafellows & SSH_OLD_DHGEX) { | 65 | kex->min = DH_GRP_MIN; |
66 | kex->max = DH_GRP_MAX; | ||
67 | kex->nbits = nbits; | ||
68 | if (ssh->compat & SSH_OLD_DHGEX) { | ||
66 | /* Old GEX request */ | 69 | /* Old GEX request */ |
67 | packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); | 70 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)) |
68 | packet_put_int(nbits); | 71 | != 0 || |
69 | min = DH_GRP_MIN; | 72 | (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || |
70 | max = DH_GRP_MAX; | 73 | (r = sshpkt_send(ssh)) != 0) |
71 | 74 | goto out; | |
72 | debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", nbits); | 75 | debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD(%u) sent", kex->nbits); |
73 | } else { | 76 | } else { |
74 | /* New GEX request */ | 77 | /* New GEX request */ |
75 | min = DH_GRP_MIN; | 78 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST)) != 0 || |
76 | max = DH_GRP_MAX; | 79 | (r = sshpkt_put_u32(ssh, kex->min)) != 0 || |
77 | packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); | 80 | (r = sshpkt_put_u32(ssh, kex->nbits)) != 0 || |
78 | packet_put_int(min); | 81 | (r = sshpkt_put_u32(ssh, kex->max)) != 0 || |
79 | packet_put_int(nbits); | 82 | (r = sshpkt_send(ssh)) != 0) |
80 | packet_put_int(max); | 83 | goto out; |
81 | |||
82 | debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent", | 84 | debug("SSH2_MSG_KEX_DH_GEX_REQUEST(%u<%u<%u) sent", |
83 | min, nbits, max); | 85 | kex->min, kex->nbits, kex->max); |
84 | } | 86 | } |
85 | #ifdef DEBUG_KEXDH | 87 | #ifdef DEBUG_KEXDH |
86 | fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", | 88 | fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n", |
87 | min, nbits, max); | 89 | kex->min, kex->nbits, kex->max); |
88 | #endif | 90 | #endif |
89 | packet_send(); | 91 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, |
90 | 92 | &input_kex_dh_gex_group); | |
91 | debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP"); | 93 | r = 0; |
92 | packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP); | 94 | out: |
95 | return r; | ||
96 | } | ||
93 | 97 | ||
94 | if ((p = BN_new()) == NULL) | 98 | static int |
95 | fatal("BN_new"); | 99 | input_kex_dh_gex_group(int type, u_int32_t seq, void *ctxt) |
96 | packet_get_bignum2(p); | 100 | { |
97 | if ((g = BN_new()) == NULL) | 101 | struct ssh *ssh = ctxt; |
98 | fatal("BN_new"); | 102 | struct kex *kex = ssh->kex; |
99 | packet_get_bignum2(g); | 103 | BIGNUM *p = NULL, *g = NULL; |
100 | packet_check_eom(); | 104 | int r, bits; |
101 | 105 | ||
102 | if (BN_num_bits(p) < min || BN_num_bits(p) > max) | 106 | debug("got SSH2_MSG_KEX_DH_GEX_GROUP"); |
103 | fatal("DH_GEX group out of range: %d !< %d !< %d", | ||
104 | min, BN_num_bits(p), max); | ||
105 | 107 | ||
106 | dh = dh_new_group(g, p); | 108 | if ((p = BN_new()) == NULL || |
107 | dh_gen_key(dh, kex->we_need * 8); | 109 | (g = BN_new()) == NULL) { |
110 | r = SSH_ERR_ALLOC_FAIL; | ||
111 | goto out; | ||
112 | } | ||
113 | if ((r = sshpkt_get_bignum2(ssh, p)) != 0 || | ||
114 | (r = sshpkt_get_bignum2(ssh, g)) != 0 || | ||
115 | (r = sshpkt_get_end(ssh)) != 0) | ||
116 | goto out; | ||
117 | if ((bits = BN_num_bits(p)) < 0 || | ||
118 | (u_int)bits < kex->min || (u_int)bits > kex->max) { | ||
119 | r = SSH_ERR_DH_GEX_OUT_OF_RANGE; | ||
120 | goto out; | ||
121 | } | ||
122 | if ((kex->dh = dh_new_group(g, p)) == NULL) { | ||
123 | r = SSH_ERR_ALLOC_FAIL; | ||
124 | goto out; | ||
125 | } | ||
126 | p = g = NULL; /* belong to kex->dh now */ | ||
108 | 127 | ||
128 | /* generate and send 'e', client DH public key */ | ||
129 | if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0 || | ||
130 | (r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_INIT)) != 0 || | ||
131 | (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || | ||
132 | (r = sshpkt_send(ssh)) != 0) | ||
133 | goto out; | ||
134 | debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); | ||
109 | #ifdef DEBUG_KEXDH | 135 | #ifdef DEBUG_KEXDH |
110 | DHparams_print_fp(stderr, dh); | 136 | DHparams_print_fp(stderr, kex->dh); |
111 | fprintf(stderr, "pub= "); | 137 | fprintf(stderr, "pub= "); |
112 | BN_print_fp(stderr, dh->pub_key); | 138 | BN_print_fp(stderr, kex->dh->pub_key); |
113 | fprintf(stderr, "\n"); | 139 | fprintf(stderr, "\n"); |
114 | #endif | 140 | #endif |
141 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_GROUP, NULL); | ||
142 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REPLY, &input_kex_dh_gex_reply); | ||
143 | r = 0; | ||
144 | out: | ||
145 | if (p) | ||
146 | BN_clear_free(p); | ||
147 | if (g) | ||
148 | BN_clear_free(g); | ||
149 | return r; | ||
150 | } | ||
115 | 151 | ||
116 | debug("SSH2_MSG_KEX_DH_GEX_INIT sent"); | 152 | static int |
117 | /* generate and send 'e', client DH public key */ | 153 | input_kex_dh_gex_reply(int type, u_int32_t seq, void *ctxt) |
118 | packet_start(SSH2_MSG_KEX_DH_GEX_INIT); | 154 | { |
119 | packet_put_bignum2(dh->pub_key); | 155 | struct ssh *ssh = ctxt; |
120 | packet_send(); | 156 | struct kex *kex = ssh->kex; |
121 | 157 | BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; | |
122 | debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY"); | 158 | struct sshkey *server_host_key = NULL; |
123 | packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY); | 159 | u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; |
160 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
161 | size_t klen = 0, slen, sbloblen, hashlen; | ||
162 | int kout, r; | ||
124 | 163 | ||
164 | debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); | ||
165 | if (kex->verify_host_key == NULL) { | ||
166 | r = SSH_ERR_INVALID_ARGUMENT; | ||
167 | goto out; | ||
168 | } | ||
125 | /* key, cert */ | 169 | /* key, cert */ |
126 | server_host_key_blob = packet_get_string(&sbloblen); | 170 | if ((r = sshpkt_get_string(ssh, &server_host_key_blob, |
127 | server_host_key = key_from_blob(server_host_key_blob, sbloblen); | 171 | &sbloblen)) != 0 || |
128 | if (server_host_key == NULL) | 172 | (r = sshkey_from_blob(server_host_key_blob, sbloblen, |
129 | fatal("cannot decode server_host_key_blob"); | 173 | &server_host_key)) != 0) |
130 | if (server_host_key->type != kex->hostkey_type) | 174 | goto out; |
131 | fatal("type mismatch for decoded server_host_key_blob"); | 175 | if (server_host_key->type != kex->hostkey_type) { |
132 | if (kex->verify_host_key == NULL) | 176 | r = SSH_ERR_KEY_TYPE_MISMATCH; |
133 | fatal("cannot verify server_host_key"); | 177 | goto out; |
134 | if (kex->verify_host_key(server_host_key) == -1) | 178 | } |
135 | fatal("server_host_key verification failed"); | 179 | if (kex->verify_host_key(server_host_key, ssh) == -1) { |
136 | 180 | r = SSH_ERR_SIGNATURE_INVALID; | |
181 | goto out; | ||
182 | } | ||
137 | /* DH parameter f, server public DH key */ | 183 | /* DH parameter f, server public DH key */ |
138 | if ((dh_server_pub = BN_new()) == NULL) | 184 | if ((dh_server_pub = BN_new()) == NULL) { |
139 | fatal("dh_server_pub == NULL"); | 185 | r = SSH_ERR_ALLOC_FAIL; |
140 | packet_get_bignum2(dh_server_pub); | 186 | goto out; |
141 | 187 | } | |
188 | /* signed H */ | ||
189 | if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || | ||
190 | (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || | ||
191 | (r = sshpkt_get_end(ssh)) != 0) | ||
192 | goto out; | ||
142 | #ifdef DEBUG_KEXDH | 193 | #ifdef DEBUG_KEXDH |
143 | fprintf(stderr, "dh_server_pub= "); | 194 | fprintf(stderr, "dh_server_pub= "); |
144 | BN_print_fp(stderr, dh_server_pub); | 195 | BN_print_fp(stderr, dh_server_pub); |
145 | fprintf(stderr, "\n"); | 196 | fprintf(stderr, "\n"); |
146 | debug("bits %d", BN_num_bits(dh_server_pub)); | 197 | debug("bits %d", BN_num_bits(dh_server_pub)); |
147 | #endif | 198 | #endif |
199 | if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { | ||
200 | sshpkt_disconnect(ssh, "bad server public DH value"); | ||
201 | r = SSH_ERR_MESSAGE_INCOMPLETE; | ||
202 | goto out; | ||
203 | } | ||
148 | 204 | ||
149 | /* signed H */ | 205 | klen = DH_size(kex->dh); |
150 | signature = packet_get_string(&slen); | 206 | if ((kbuf = malloc(klen)) == NULL || |
151 | packet_check_eom(); | 207 | (shared_secret = BN_new()) == NULL) { |
152 | 208 | r = SSH_ERR_ALLOC_FAIL; | |
153 | if (!dh_pub_is_valid(dh, dh_server_pub)) | 209 | goto out; |
154 | packet_disconnect("bad server public DH value"); | 210 | } |
155 | 211 | if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || | |
156 | klen = DH_size(dh); | 212 | BN_bin2bn(kbuf, kout, shared_secret) == NULL) { |
157 | kbuf = xmalloc(klen); | 213 | r = SSH_ERR_LIBCRYPTO_ERROR; |
158 | if ((kout = DH_compute_key(kbuf, dh_server_pub, dh)) < 0) | 214 | goto out; |
159 | fatal("DH_compute_key: failed"); | 215 | } |
160 | #ifdef DEBUG_KEXDH | 216 | #ifdef DEBUG_KEXDH |
161 | dump_digest("shared secret", kbuf, kout); | 217 | dump_digest("shared secret", kbuf, kout); |
162 | #endif | 218 | #endif |
163 | if ((shared_secret = BN_new()) == NULL) | 219 | if (ssh->compat & SSH_OLD_DHGEX) |
164 | fatal("kexgex_client: BN_new failed"); | 220 | kex->min = kex->max = -1; |
165 | if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) | ||
166 | fatal("kexgex_client: BN_bin2bn failed"); | ||
167 | explicit_bzero(kbuf, klen); | ||
168 | free(kbuf); | ||
169 | |||
170 | if (datafellows & SSH_OLD_DHGEX) | ||
171 | min = max = -1; | ||
172 | 221 | ||
173 | /* calc and verify H */ | 222 | /* calc and verify H */ |
174 | kexgex_hash( | 223 | hashlen = sizeof(hash); |
224 | if ((r = kexgex_hash( | ||
175 | kex->hash_alg, | 225 | kex->hash_alg, |
176 | kex->client_version_string, | 226 | kex->client_version_string, |
177 | kex->server_version_string, | 227 | kex->server_version_string, |
178 | buffer_ptr(kex->my), buffer_len(kex->my), | 228 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), |
179 | buffer_ptr(kex->peer), buffer_len(kex->peer), | 229 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), |
180 | server_host_key_blob, sbloblen, | 230 | server_host_key_blob, sbloblen, |
181 | min, nbits, max, | 231 | kex->min, kex->nbits, kex->max, |
182 | dh->p, dh->g, | 232 | kex->dh->p, kex->dh->g, |
183 | dh->pub_key, | 233 | kex->dh->pub_key, |
184 | dh_server_pub, | 234 | dh_server_pub, |
185 | shared_secret, | 235 | shared_secret, |
186 | &hash, &hashlen | 236 | hash, &hashlen)) != 0) |
187 | ); | 237 | goto out; |
188 | |||
189 | /* have keys, free DH */ | ||
190 | DH_free(dh); | ||
191 | free(server_host_key_blob); | ||
192 | BN_clear_free(dh_server_pub); | ||
193 | 238 | ||
194 | if (key_verify(server_host_key, signature, slen, hash, hashlen) != 1) | 239 | if ((r = sshkey_verify(server_host_key, signature, slen, hash, |
195 | fatal("key_verify failed for server_host_key"); | 240 | hashlen, ssh->compat)) != 0) |
196 | key_free(server_host_key); | 241 | goto out; |
197 | free(signature); | ||
198 | 242 | ||
199 | /* save session id */ | 243 | /* save session id */ |
200 | if (kex->session_id == NULL) { | 244 | if (kex->session_id == NULL) { |
201 | kex->session_id_len = hashlen; | 245 | kex->session_id_len = hashlen; |
202 | kex->session_id = xmalloc(kex->session_id_len); | 246 | kex->session_id = malloc(kex->session_id_len); |
247 | if (kex->session_id == NULL) { | ||
248 | r = SSH_ERR_ALLOC_FAIL; | ||
249 | goto out; | ||
250 | } | ||
203 | memcpy(kex->session_id, hash, kex->session_id_len); | 251 | memcpy(kex->session_id, hash, kex->session_id_len); |
204 | } | 252 | } |
205 | kex_derive_keys_bn(kex, hash, hashlen, shared_secret); | ||
206 | BN_clear_free(shared_secret); | ||
207 | 253 | ||
208 | kex_finish(kex); | 254 | if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) |
255 | r = kex_send_newkeys(ssh); | ||
256 | out: | ||
257 | explicit_bzero(hash, sizeof(hash)); | ||
258 | DH_free(kex->dh); | ||
259 | kex->dh = NULL; | ||
260 | if (dh_server_pub) | ||
261 | BN_clear_free(dh_server_pub); | ||
262 | if (kbuf) { | ||
263 | explicit_bzero(kbuf, klen); | ||
264 | free(kbuf); | ||
265 | } | ||
266 | if (shared_secret) | ||
267 | BN_clear_free(shared_secret); | ||
268 | sshkey_free(server_host_key); | ||
269 | free(server_host_key_blob); | ||
270 | free(signature); | ||
271 | return r; | ||
209 | } | 272 | } |
210 | #endif /* WITH_OPENSSL */ | 273 | #endif /* WITH_OPENSSL */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexgexs.c,v 1.20 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: kexgexs.c,v 1.21 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Niels Provos. All rights reserved. | 3 | * Copyright (c) 2000 Niels Provos. All rights reserved. |
4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2001 Markus Friedl. All rights reserved. |
@@ -37,10 +37,9 @@ | |||
37 | 37 | ||
38 | #include <openssl/dh.h> | 38 | #include <openssl/dh.h> |
39 | 39 | ||
40 | #include "xmalloc.h" | 40 | #include "sshkey.h" |
41 | #include "buffer.h" | ||
42 | #include "key.h" | ||
43 | #include "cipher.h" | 41 | #include "cipher.h" |
42 | #include "digest.h" | ||
44 | #include "kex.h" | 43 | #include "kex.h" |
45 | #include "log.h" | 44 | #include "log.h" |
46 | #include "packet.h" | 45 | #include "packet.h" |
@@ -51,33 +50,43 @@ | |||
51 | #include "ssh-gss.h" | 50 | #include "ssh-gss.h" |
52 | #endif | 51 | #endif |
53 | #include "monitor_wrap.h" | 52 | #include "monitor_wrap.h" |
53 | #include "dispatch.h" | ||
54 | #include "ssherr.h" | ||
55 | #include "sshbuf.h" | ||
54 | 56 | ||
55 | void | 57 | static int input_kex_dh_gex_request(int, u_int32_t, void *); |
56 | kexgex_server(Kex *kex) | 58 | static int input_kex_dh_gex_init(int, u_int32_t, void *); |
59 | |||
60 | int | ||
61 | kexgex_server(struct ssh *ssh) | ||
57 | { | 62 | { |
58 | BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; | 63 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, |
59 | Key *server_host_public, *server_host_private; | 64 | &input_kex_dh_gex_request); |
60 | DH *dh; | 65 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_REQUEST, |
61 | u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL; | 66 | &input_kex_dh_gex_request); |
62 | u_int sbloblen, klen, slen, hashlen; | 67 | debug("expecting SSH2_MSG_KEX_DH_GEX_REQUEST"); |
63 | int omin = -1, min = -1, omax = -1, max = -1, onbits = -1, nbits = -1; | 68 | return 0; |
64 | int type, kout; | 69 | } |
70 | |||
71 | static int | ||
72 | input_kex_dh_gex_request(int type, u_int32_t seq, void *ctxt) | ||
73 | { | ||
74 | struct ssh *ssh = ctxt; | ||
75 | struct kex *kex = ssh->kex; | ||
76 | int r; | ||
77 | u_int min = 0, max = 0, nbits = 0; | ||
65 | 78 | ||
66 | if (kex->load_host_public_key == NULL || | ||
67 | kex->load_host_private_key == NULL) | ||
68 | fatal("Cannot load hostkey"); | ||
69 | server_host_public = kex->load_host_public_key(kex->hostkey_type); | ||
70 | if (server_host_public == NULL) | ||
71 | fatal("Unsupported hostkey type %d", kex->hostkey_type); | ||
72 | server_host_private = kex->load_host_private_key(kex->hostkey_type); | ||
73 | |||
74 | type = packet_read(); | ||
75 | switch (type) { | 79 | switch (type) { |
76 | case SSH2_MSG_KEX_DH_GEX_REQUEST: | 80 | case SSH2_MSG_KEX_DH_GEX_REQUEST: |
77 | debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); | 81 | debug("SSH2_MSG_KEX_DH_GEX_REQUEST received"); |
78 | omin = min = packet_get_int(); | 82 | if ((r = sshpkt_get_u32(ssh, &min)) != 0 || |
79 | onbits = nbits = packet_get_int(); | 83 | (r = sshpkt_get_u32(ssh, &nbits)) != 0 || |
80 | omax = max = packet_get_int(); | 84 | (r = sshpkt_get_u32(ssh, &max)) != 0 || |
85 | (r = sshpkt_get_end(ssh)) != 0) | ||
86 | goto out; | ||
87 | kex->nbits = nbits; | ||
88 | kex->min = min; | ||
89 | kex->max = max; | ||
81 | min = MAX(DH_GRP_MIN, min); | 90 | min = MAX(DH_GRP_MIN, min); |
82 | max = MIN(DH_GRP_MAX, max); | 91 | max = MIN(DH_GRP_MAX, max); |
83 | nbits = MAX(DH_GRP_MIN, nbits); | 92 | nbits = MAX(DH_GRP_MIN, nbits); |
@@ -85,45 +94,88 @@ kexgex_server(Kex *kex) | |||
85 | break; | 94 | break; |
86 | case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: | 95 | case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD: |
87 | debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); | 96 | debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received"); |
88 | onbits = nbits = packet_get_int(); | 97 | if ((r = sshpkt_get_u32(ssh, &nbits)) != 0 || |
98 | (r = sshpkt_get_end(ssh)) != 0) | ||
99 | goto out; | ||
100 | kex->nbits = nbits; | ||
89 | /* unused for old GEX */ | 101 | /* unused for old GEX */ |
90 | omin = min = DH_GRP_MIN; | 102 | kex->min = min = DH_GRP_MIN; |
91 | omax = max = DH_GRP_MAX; | 103 | kex->max = max = DH_GRP_MAX; |
92 | break; | 104 | break; |
93 | default: | 105 | default: |
94 | fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type); | 106 | r = SSH_ERR_INVALID_ARGUMENT; |
107 | goto out; | ||
95 | } | 108 | } |
96 | packet_check_eom(); | ||
97 | 109 | ||
98 | if (omax < omin || onbits < omin || omax < onbits) | 110 | if (kex->max < kex->min || kex->nbits < kex->min || |
99 | fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", | 111 | kex->max < kex->nbits) { |
100 | omin, onbits, omax); | 112 | r = SSH_ERR_DH_GEX_OUT_OF_RANGE; |
113 | goto out; | ||
114 | } | ||
101 | 115 | ||
102 | /* Contact privileged parent */ | 116 | /* Contact privileged parent */ |
103 | dh = PRIVSEP(choose_dh(min, nbits, max)); | 117 | kex->dh = PRIVSEP(choose_dh(min, nbits, max)); |
104 | if (dh == NULL) | 118 | if (kex->dh == NULL) { |
105 | packet_disconnect("Protocol error: no matching DH grp found"); | 119 | sshpkt_disconnect(ssh, "no matching DH grp found"); |
106 | 120 | r = SSH_ERR_ALLOC_FAIL; | |
121 | goto out; | ||
122 | } | ||
107 | debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); | 123 | debug("SSH2_MSG_KEX_DH_GEX_GROUP sent"); |
108 | packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); | 124 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_GROUP)) != 0 || |
109 | packet_put_bignum2(dh->p); | 125 | (r = sshpkt_put_bignum2(ssh, kex->dh->p)) != 0 || |
110 | packet_put_bignum2(dh->g); | 126 | (r = sshpkt_put_bignum2(ssh, kex->dh->g)) != 0 || |
111 | packet_send(); | 127 | (r = sshpkt_send(ssh)) != 0) |
112 | 128 | goto out; | |
113 | /* flush */ | ||
114 | packet_write_wait(); | ||
115 | 129 | ||
116 | /* Compute our exchange value in parallel with the client */ | 130 | /* Compute our exchange value in parallel with the client */ |
117 | dh_gen_key(dh, kex->we_need * 8); | 131 | if ((r = dh_gen_key(kex->dh, kex->we_need * 8)) != 0) |
132 | goto out; | ||
133 | |||
134 | /* old KEX does not use min/max in kexgex_hash() */ | ||
135 | if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) | ||
136 | kex->min = kex->max = -1; | ||
118 | 137 | ||
119 | debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); | 138 | debug("expecting SSH2_MSG_KEX_DH_GEX_INIT"); |
120 | packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT); | 139 | ssh_dispatch_set(ssh, SSH2_MSG_KEX_DH_GEX_INIT, &input_kex_dh_gex_init); |
140 | r = 0; | ||
141 | out: | ||
142 | return r; | ||
143 | } | ||
144 | |||
145 | static int | ||
146 | input_kex_dh_gex_init(int type, u_int32_t seq, void *ctxt) | ||
147 | { | ||
148 | struct ssh *ssh = ctxt; | ||
149 | struct kex *kex = ssh->kex; | ||
150 | BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; | ||
151 | struct sshkey *server_host_public, *server_host_private; | ||
152 | u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; | ||
153 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | ||
154 | size_t sbloblen, slen; | ||
155 | size_t klen = 0, hashlen; | ||
156 | int kout, r; | ||
157 | |||
158 | if (kex->load_host_public_key == NULL || | ||
159 | kex->load_host_private_key == NULL) { | ||
160 | r = SSH_ERR_INVALID_ARGUMENT; | ||
161 | goto out; | ||
162 | } | ||
163 | if ((server_host_public = kex->load_host_public_key(kex->hostkey_type, | ||
164 | ssh)) == NULL || | ||
165 | (server_host_private = kex->load_host_private_key(kex->hostkey_type, | ||
166 | ssh)) == NULL) { | ||
167 | r = SSH_ERR_NO_HOSTKEY_LOADED; | ||
168 | goto out; | ||
169 | } | ||
121 | 170 | ||
122 | /* key, cert */ | 171 | /* key, cert */ |
123 | if ((dh_client_pub = BN_new()) == NULL) | 172 | if ((dh_client_pub = BN_new()) == NULL) { |
124 | fatal("dh_client_pub == NULL"); | 173 | r = SSH_ERR_ALLOC_FAIL; |
125 | packet_get_bignum2(dh_client_pub); | 174 | goto out; |
126 | packet_check_eom(); | 175 | } |
176 | if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 || | ||
177 | (r = sshpkt_get_end(ssh)) != 0) | ||
178 | goto out; | ||
127 | 179 | ||
128 | #ifdef DEBUG_KEXDH | 180 | #ifdef DEBUG_KEXDH |
129 | fprintf(stderr, "dh_client_pub= "); | 181 | fprintf(stderr, "dh_client_pub= "); |
@@ -133,79 +185,92 @@ kexgex_server(Kex *kex) | |||
133 | #endif | 185 | #endif |
134 | 186 | ||
135 | #ifdef DEBUG_KEXDH | 187 | #ifdef DEBUG_KEXDH |
136 | DHparams_print_fp(stderr, dh); | 188 | DHparams_print_fp(stderr, kex->dh); |
137 | fprintf(stderr, "pub= "); | 189 | fprintf(stderr, "pub= "); |
138 | BN_print_fp(stderr, dh->pub_key); | 190 | BN_print_fp(stderr, kex->dh->pub_key); |
139 | fprintf(stderr, "\n"); | 191 | fprintf(stderr, "\n"); |
140 | #endif | 192 | #endif |
141 | if (!dh_pub_is_valid(dh, dh_client_pub)) | 193 | if (!dh_pub_is_valid(kex->dh, dh_client_pub)) { |
142 | packet_disconnect("bad client public DH value"); | 194 | sshpkt_disconnect(ssh, "bad client public DH value"); |
195 | r = SSH_ERR_MESSAGE_INCOMPLETE; | ||
196 | goto out; | ||
197 | } | ||
143 | 198 | ||
144 | klen = DH_size(dh); | 199 | klen = DH_size(kex->dh); |
145 | kbuf = xmalloc(klen); | 200 | if ((kbuf = malloc(klen)) == NULL || |
146 | if ((kout = DH_compute_key(kbuf, dh_client_pub, dh)) < 0) | 201 | (shared_secret = BN_new()) == NULL) { |
147 | fatal("DH_compute_key: failed"); | 202 | r = SSH_ERR_ALLOC_FAIL; |
203 | goto out; | ||
204 | } | ||
205 | if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 || | ||
206 | BN_bin2bn(kbuf, kout, shared_secret) == NULL) { | ||
207 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
208 | goto out; | ||
209 | } | ||
148 | #ifdef DEBUG_KEXDH | 210 | #ifdef DEBUG_KEXDH |
149 | dump_digest("shared secret", kbuf, kout); | 211 | dump_digest("shared secret", kbuf, kout); |
150 | #endif | 212 | #endif |
151 | if ((shared_secret = BN_new()) == NULL) | 213 | if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, |
152 | fatal("kexgex_server: BN_new failed"); | 214 | &sbloblen)) != 0) |
153 | if (BN_bin2bn(kbuf, kout, shared_secret) == NULL) | 215 | goto out; |
154 | fatal("kexgex_server: BN_bin2bn failed"); | ||
155 | explicit_bzero(kbuf, klen); | ||
156 | free(kbuf); | ||
157 | |||
158 | key_to_blob(server_host_public, &server_host_key_blob, &sbloblen); | ||
159 | |||
160 | if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) | ||
161 | omin = min = omax = max = -1; | ||
162 | |||
163 | /* calc H */ | 216 | /* calc H */ |
164 | kexgex_hash( | 217 | hashlen = sizeof(hash); |
218 | if ((r = kexgex_hash( | ||
165 | kex->hash_alg, | 219 | kex->hash_alg, |
166 | kex->client_version_string, | 220 | kex->client_version_string, |
167 | kex->server_version_string, | 221 | kex->server_version_string, |
168 | buffer_ptr(kex->peer), buffer_len(kex->peer), | 222 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), |
169 | buffer_ptr(kex->my), buffer_len(kex->my), | 223 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), |
170 | server_host_key_blob, sbloblen, | 224 | server_host_key_blob, sbloblen, |
171 | omin, onbits, omax, | 225 | kex->min, kex->nbits, kex->max, |
172 | dh->p, dh->g, | 226 | kex->dh->p, kex->dh->g, |
173 | dh_client_pub, | 227 | dh_client_pub, |
174 | dh->pub_key, | 228 | kex->dh->pub_key, |
175 | shared_secret, | 229 | shared_secret, |
176 | &hash, &hashlen | 230 | hash, &hashlen)) != 0) |
177 | ); | 231 | goto out; |
178 | BN_clear_free(dh_client_pub); | ||
179 | 232 | ||
180 | /* save session id := H */ | 233 | /* save session id := H */ |
181 | if (kex->session_id == NULL) { | 234 | if (kex->session_id == NULL) { |
182 | kex->session_id_len = hashlen; | 235 | kex->session_id_len = hashlen; |
183 | kex->session_id = xmalloc(kex->session_id_len); | 236 | kex->session_id = malloc(kex->session_id_len); |
237 | if (kex->session_id == NULL) { | ||
238 | r = SSH_ERR_ALLOC_FAIL; | ||
239 | goto out; | ||
240 | } | ||
184 | memcpy(kex->session_id, hash, kex->session_id_len); | 241 | memcpy(kex->session_id, hash, kex->session_id_len); |
185 | } | 242 | } |
186 | 243 | ||
187 | /* sign H */ | 244 | /* sign H */ |
188 | kex->sign(server_host_private, server_host_public, &signature, &slen, | 245 | if ((r = kex->sign(server_host_private, server_host_public, |
189 | hash, hashlen); | 246 | &signature, &slen, hash, hashlen, ssh->compat)) < 0) |
247 | goto out; | ||
190 | 248 | ||
191 | /* destroy_sensitive_data(); */ | 249 | /* destroy_sensitive_data(); */ |
192 | 250 | ||
193 | /* send server hostkey, DH pubkey 'f' and singed H */ | 251 | /* send server hostkey, DH pubkey 'f' and singed H */ |
194 | debug("SSH2_MSG_KEX_DH_GEX_REPLY sent"); | 252 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 || |
195 | packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); | 253 | (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || |
196 | packet_put_string(server_host_key_blob, sbloblen); | 254 | (r = sshpkt_put_bignum2(ssh, kex->dh->pub_key)) != 0 || /* f */ |
197 | packet_put_bignum2(dh->pub_key); /* f */ | 255 | (r = sshpkt_put_string(ssh, signature, slen)) != 0 || |
198 | packet_put_string(signature, slen); | 256 | (r = sshpkt_send(ssh)) != 0) |
199 | packet_send(); | 257 | goto out; |
200 | 258 | ||
201 | free(signature); | 259 | if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) |
260 | r = kex_send_newkeys(ssh); | ||
261 | out: | ||
262 | DH_free(kex->dh); | ||
263 | kex->dh = NULL; | ||
264 | if (dh_client_pub) | ||
265 | BN_clear_free(dh_client_pub); | ||
266 | if (kbuf) { | ||
267 | explicit_bzero(kbuf, klen); | ||
268 | free(kbuf); | ||
269 | } | ||
270 | if (shared_secret) | ||
271 | BN_clear_free(shared_secret); | ||
202 | free(server_host_key_blob); | 272 | free(server_host_key_blob); |
203 | /* have keys, free DH */ | 273 | free(signature); |
204 | DH_free(dh); | 274 | return r; |
205 | |||
206 | kex_derive_keys_bn(kex, hash, hashlen, shared_secret); | ||
207 | BN_clear_free(shared_secret); | ||
208 | |||
209 | kex_finish(kex); | ||
210 | } | 275 | } |
211 | #endif /* WITH_OPENSSL */ | 276 | #endif /* WITH_OPENSSL */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor.c,v 1.139 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: monitor.c,v 1.140 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -717,7 +717,7 @@ mm_answer_sign(int sock, Buffer *m) | |||
717 | datafellows)) != 0) | 717 | datafellows)) != 0) |
718 | fatal("%s: sshkey_sign failed: %s", | 718 | fatal("%s: sshkey_sign failed: %s", |
719 | __func__, ssh_err(r)); | 719 | __func__, ssh_err(r)); |
720 | } else if ((key = get_hostkey_public_by_index(keyid)) != NULL && | 720 | } else if ((key = get_hostkey_public_by_index(keyid, active_state)) != NULL && |
721 | auth_sock > 0) { | 721 | auth_sock > 0) { |
722 | if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, | 722 | if ((r = ssh_agent_sign(auth_sock, key, &signature, &siglen, |
723 | p, datlen, datafellows)) != 0) { | 723 | p, datlen, datafellows)) != 0) { |
diff --git a/monitor_wrap.c b/monitor_wrap.c index 84df481d8..c0935dc69 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor_wrap.c,v 1.82 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: monitor_wrap.c,v 1.83 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -221,13 +221,13 @@ mm_choose_dh(int min, int nbits, int max) | |||
221 | int | 221 | int |
222 | mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) | 222 | mm_key_sign(Key *key, u_char **sigp, u_int *lenp, u_char *data, u_int datalen) |
223 | { | 223 | { |
224 | Kex *kex = *pmonitor->m_pkex; | 224 | struct kex *kex = *pmonitor->m_pkex; |
225 | Buffer m; | 225 | Buffer m; |
226 | 226 | ||
227 | debug3("%s entering", __func__); | 227 | debug3("%s entering", __func__); |
228 | 228 | ||
229 | buffer_init(&m); | 229 | buffer_init(&m); |
230 | buffer_put_int(&m, kex->host_key_index(key)); | 230 | buffer_put_int(&m, kex->host_key_index(key, active_state)); |
231 | buffer_put_string(&m, data, datalen); | 231 | buffer_put_string(&m, data, datalen); |
232 | 232 | ||
233 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SIGN, &m); | 233 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_SIGN, &m); |
diff --git a/serverloop.c b/serverloop.c index edf6a813f..83a1e010d 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: serverloop.c,v 1.174 2015/01/19 20:07:45 markus Exp $ */ | 1 | /* $OpenBSD: serverloop.c,v 1.175 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -544,7 +544,7 @@ drain_output(void) | |||
544 | static void | 544 | static void |
545 | process_buffered_input_packets(void) | 545 | process_buffered_input_packets(void) |
546 | { | 546 | { |
547 | dispatch_run(DISPATCH_NONBLOCK, NULL, compat20 ? active_state->kex : NULL); | 547 | dispatch_run(DISPATCH_NONBLOCK, NULL, active_state); |
548 | } | 548 | } |
549 | 549 | ||
550 | /* | 550 | /* |
@@ -874,7 +874,7 @@ server_loop2(Authctxt *authctxt) | |||
874 | if (packet_need_rekeying()) { | 874 | if (packet_need_rekeying()) { |
875 | debug("need rekeying"); | 875 | debug("need rekeying"); |
876 | active_state->kex->done = 0; | 876 | active_state->kex->done = 0; |
877 | kex_send_kexinit(active_state->kex); | 877 | kex_send_kexinit(active_state); |
878 | } | 878 | } |
879 | } | 879 | } |
880 | process_input(readset); | 880 | process_input(readset); |
diff --git a/ssh-keyscan.c b/ssh-keyscan.c index 84301b6ff..223ac58f1 100644 --- a/ssh-keyscan.c +++ b/ssh-keyscan.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keyscan.c,v 1.93 2014/12/11 08:20:09 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keyscan.c,v 1.94 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. | 3 | * Copyright 1995, 1996 by David Mazieres <dm@lcs.mit.edu>. |
4 | * | 4 | * |
@@ -100,7 +100,7 @@ typedef struct Connection { | |||
100 | char *c_namelist; /* Pointer to other possible addresses */ | 100 | char *c_namelist; /* Pointer to other possible addresses */ |
101 | char *c_output_name; /* Hostname of connection for output */ | 101 | char *c_output_name; /* Hostname of connection for output */ |
102 | char *c_data; /* Data read from this fd */ | 102 | char *c_data; /* Data read from this fd */ |
103 | Kex *c_kex; /* The key-exchange struct for ssh2 */ | 103 | struct kex *c_kex; /* The key-exchange struct for ssh2 */ |
104 | struct timeval c_tv; /* Time at which connection gets aborted */ | 104 | struct timeval c_tv; /* Time at which connection gets aborted */ |
105 | TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ | 105 | TAILQ_ENTRY(Connection) c_link; /* List of connections in timeout order. */ |
106 | } con; | 106 | } con; |
@@ -221,7 +221,7 @@ keygrab_ssh1(con *c) | |||
221 | #endif | 221 | #endif |
222 | 222 | ||
223 | static int | 223 | static int |
224 | hostjump(Key *hostkey) | 224 | hostjump(Key *hostkey, struct ssh *ssh) |
225 | { | 225 | { |
226 | kexjmp_key = hostkey; | 226 | kexjmp_key = hostkey; |
227 | longjmp(kexjmp, 1); | 227 | longjmp(kexjmp, 1); |
@@ -247,7 +247,7 @@ static Key * | |||
247 | keygrab_ssh2(con *c) | 247 | keygrab_ssh2(con *c) |
248 | { | 248 | { |
249 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; | 249 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
250 | int j; | 250 | int r, j; |
251 | 251 | ||
252 | packet_set_connection(c->c_fd, c->c_fd); | 252 | packet_set_connection(c->c_fd, c->c_fd); |
253 | enable_compat20(); | 253 | enable_compat20(); |
@@ -256,7 +256,9 @@ keygrab_ssh2(con *c) | |||
256 | (c->c_keytype == KT_RSA ? "ssh-rsa" : | 256 | (c->c_keytype == KT_RSA ? "ssh-rsa" : |
257 | (c->c_keytype == KT_ED25519 ? "ssh-ed25519" : | 257 | (c->c_keytype == KT_ED25519 ? "ssh-ed25519" : |
258 | "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521")); | 258 | "ecdsa-sha2-nistp256,ecdsa-sha2-nistp384,ecdsa-sha2-nistp521")); |
259 | c->c_kex = kex_setup(myproposal); | 259 | if ((r = kex_setup(active_state, myproposal)) < 0) |
260 | fatal("%s: kex_setup: %s", __func__, ssh_err(r)); | ||
261 | c->c_kex = active_state->kex; | ||
260 | #ifdef WITH_OPENSSL | 262 | #ifdef WITH_OPENSSL |
261 | c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; | 263 | c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; |
262 | c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 264 | c->c_kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
@@ -269,7 +271,7 @@ keygrab_ssh2(con *c) | |||
269 | 271 | ||
270 | if (!(j = setjmp(kexjmp))) { | 272 | if (!(j = setjmp(kexjmp))) { |
271 | nonfatal_fatal = 1; | 273 | nonfatal_fatal = 1; |
272 | dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, c->c_kex); | 274 | dispatch_run(DISPATCH_BLOCK, &c->c_kex->done, active_state); |
273 | fprintf(stderr, "Impossible! dispatch_run() returned!\n"); | 275 | fprintf(stderr, "Impossible! dispatch_run() returned!\n"); |
274 | exit(1); | 276 | exit(1); |
275 | } | 277 | } |
diff --git a/sshconnect2.c b/sshconnect2.c index e0d129996..e5802abcc 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshconnect2.c,v 1.218 2015/01/19 20:07:45 markus Exp $ */ | 1 | /* $OpenBSD: sshconnect2.c,v 1.219 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 3 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
4 | * Copyright (c) 2008 Damien Miller. All rights reserved. | 4 | * Copyright (c) 2008 Damien Miller. All rights reserved. |
@@ -92,7 +92,7 @@ char *xxx_host; | |||
92 | struct sockaddr *xxx_hostaddr; | 92 | struct sockaddr *xxx_hostaddr; |
93 | 93 | ||
94 | static int | 94 | static int |
95 | verify_host_key_callback(Key *hostkey) | 95 | verify_host_key_callback(Key *hostkey, struct ssh *ssh) |
96 | { | 96 | { |
97 | if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) | 97 | if (verify_host_key(xxx_host, xxx_hostaddr, hostkey) == -1) |
98 | fatal("Host key verification failed."); | 98 | fatal("Host key verification failed."); |
@@ -157,7 +157,7 @@ void | |||
157 | ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | 157 | ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) |
158 | { | 158 | { |
159 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; | 159 | char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT }; |
160 | Kex *kex; | 160 | struct kex *kex; |
161 | 161 | ||
162 | xxx_host = host; | 162 | xxx_host = host; |
163 | xxx_hostaddr = hostaddr; | 163 | xxx_hostaddr = hostaddr; |
@@ -204,8 +204,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
204 | (time_t)options.rekey_interval); | 204 | (time_t)options.rekey_interval); |
205 | 205 | ||
206 | /* start key exchange */ | 206 | /* start key exchange */ |
207 | kex = kex_setup(myproposal); | 207 | kex_setup(active_state, myproposal); |
208 | active_state->kex = kex; | 208 | kex = active_state->kex; |
209 | #ifdef WITH_OPENSSL | 209 | #ifdef WITH_OPENSSL |
210 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; | 210 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client; |
211 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; | 211 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_client; |
@@ -218,7 +218,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr, u_short port) | |||
218 | kex->server_version_string=server_version_string; | 218 | kex->server_version_string=server_version_string; |
219 | kex->verify_host_key=&verify_host_key_callback; | 219 | kex->verify_host_key=&verify_host_key_callback; |
220 | 220 | ||
221 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | 221 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
222 | 222 | ||
223 | if (options.use_roaming && !kex->roaming) { | 223 | if (options.use_roaming && !kex->roaming) { |
224 | debug("Roaming not allowed by server"); | 224 | debug("Roaming not allowed by server"); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.434 2015/01/19 19:52:16 markus Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.435 2015/01/19 20:16:15 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -836,7 +836,7 @@ list_hostkey_types(void) | |||
836 | } | 836 | } |
837 | 837 | ||
838 | static Key * | 838 | static Key * |
839 | get_hostkey_by_type(int type, int need_private) | 839 | get_hostkey_by_type(int type, int need_private, struct ssh *ssh) |
840 | { | 840 | { |
841 | int i; | 841 | int i; |
842 | Key *key; | 842 | Key *key; |
@@ -865,15 +865,15 @@ get_hostkey_by_type(int type, int need_private) | |||
865 | } | 865 | } |
866 | 866 | ||
867 | Key * | 867 | Key * |
868 | get_hostkey_public_by_type(int type) | 868 | get_hostkey_public_by_type(int type, struct ssh *ssh) |
869 | { | 869 | { |
870 | return get_hostkey_by_type(type, 0); | 870 | return get_hostkey_by_type(type, 0, ssh); |
871 | } | 871 | } |
872 | 872 | ||
873 | Key * | 873 | Key * |
874 | get_hostkey_private_by_type(int type) | 874 | get_hostkey_private_by_type(int type, struct ssh *ssh) |
875 | { | 875 | { |
876 | return get_hostkey_by_type(type, 1); | 876 | return get_hostkey_by_type(type, 1, ssh); |
877 | } | 877 | } |
878 | 878 | ||
879 | Key * | 879 | Key * |
@@ -885,7 +885,7 @@ get_hostkey_by_index(int ind) | |||
885 | } | 885 | } |
886 | 886 | ||
887 | Key * | 887 | Key * |
888 | get_hostkey_public_by_index(int ind) | 888 | get_hostkey_public_by_index(int ind, struct ssh *ssh) |
889 | { | 889 | { |
890 | if (ind < 0 || ind >= options.num_host_key_files) | 890 | if (ind < 0 || ind >= options.num_host_key_files) |
891 | return (NULL); | 891 | return (NULL); |
@@ -893,7 +893,7 @@ get_hostkey_public_by_index(int ind) | |||
893 | } | 893 | } |
894 | 894 | ||
895 | int | 895 | int |
896 | get_hostkey_index(Key *key) | 896 | get_hostkey_index(Key *key, struct ssh *ssh) |
897 | { | 897 | { |
898 | int i; | 898 | int i; |
899 | 899 | ||
@@ -2432,29 +2432,30 @@ do_ssh1_kex(void) | |||
2432 | } | 2432 | } |
2433 | #endif | 2433 | #endif |
2434 | 2434 | ||
2435 | void | 2435 | int |
2436 | sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, u_int *slen, | 2436 | sshd_hostkey_sign(Key *privkey, Key *pubkey, u_char **signature, size_t *slen, |
2437 | u_char *data, u_int dlen) | 2437 | u_char *data, size_t dlen, u_int flag) |
2438 | { | 2438 | { |
2439 | int r; | 2439 | int r; |
2440 | u_int xxx_slen, xxx_dlen = dlen; | ||
2440 | 2441 | ||
2441 | if (privkey) { | 2442 | if (privkey) { |
2442 | if (PRIVSEP(key_sign(privkey, signature, slen, data, dlen) < 0)) | 2443 | if (PRIVSEP(key_sign(privkey, signature, &xxx_slen, data, xxx_dlen) < 0)) |
2443 | fatal("%s: key_sign failed", __func__); | 2444 | fatal("%s: key_sign failed", __func__); |
2445 | if (slen) | ||
2446 | *slen = xxx_slen; | ||
2444 | } else if (use_privsep) { | 2447 | } else if (use_privsep) { |
2445 | if (mm_key_sign(pubkey, signature, slen, data, dlen) < 0) | 2448 | if (mm_key_sign(pubkey, signature, &xxx_slen, data, xxx_dlen) < 0) |
2446 | fatal("%s: pubkey_sign failed", __func__); | 2449 | fatal("%s: pubkey_sign failed", __func__); |
2450 | if (slen) | ||
2451 | *slen = xxx_slen; | ||
2447 | } else { | 2452 | } else { |
2448 | size_t xxx_slen; | 2453 | if ((r = ssh_agent_sign(auth_sock, pubkey, signature, slen, |
2449 | |||
2450 | if ((r = ssh_agent_sign(auth_sock, pubkey, signature, &xxx_slen, | ||
2451 | data, dlen, datafellows)) != 0) | 2454 | data, dlen, datafellows)) != 0) |
2452 | fatal("%s: ssh_agent_sign failed: %s", | 2455 | fatal("%s: ssh_agent_sign failed: %s", |
2453 | __func__, ssh_err(r)); | 2456 | __func__, ssh_err(r)); |
2454 | /* XXX: Old API is u_int; new size_t */ | ||
2455 | if (slen != NULL) | ||
2456 | *slen = xxx_slen; | ||
2457 | } | 2457 | } |
2458 | return 0; | ||
2458 | } | 2459 | } |
2459 | 2460 | ||
2460 | /* | 2461 | /* |
@@ -2464,7 +2465,7 @@ static void | |||
2464 | do_ssh2_kex(void) | 2465 | do_ssh2_kex(void) |
2465 | { | 2466 | { |
2466 | char *myproposal[PROPOSAL_MAX] = { KEX_SERVER }; | 2467 | char *myproposal[PROPOSAL_MAX] = { KEX_SERVER }; |
2467 | Kex *kex; | 2468 | struct kex *kex; |
2468 | 2469 | ||
2469 | if (options.ciphers != NULL) { | 2470 | if (options.ciphers != NULL) { |
2470 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = | 2471 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
@@ -2500,8 +2501,8 @@ do_ssh2_kex(void) | |||
2500 | list_hostkey_types()); | 2501 | list_hostkey_types()); |
2501 | 2502 | ||
2502 | /* start key exchange */ | 2503 | /* start key exchange */ |
2503 | kex = kex_setup(myproposal); | 2504 | kex_setup(active_state, myproposal); |
2504 | active_state->kex = kex; | 2505 | kex = active_state->kex; |
2505 | #ifdef WITH_OPENSSL | 2506 | #ifdef WITH_OPENSSL |
2506 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; | 2507 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; |
2507 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; | 2508 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; |
@@ -2518,7 +2519,7 @@ do_ssh2_kex(void) | |||
2518 | kex->host_key_index=&get_hostkey_index; | 2519 | kex->host_key_index=&get_hostkey_index; |
2519 | kex->sign = sshd_hostkey_sign; | 2520 | kex->sign = sshd_hostkey_sign; |
2520 | 2521 | ||
2521 | dispatch_run(DISPATCH_BLOCK, &kex->done, kex); | 2522 | dispatch_run(DISPATCH_BLOCK, &kex->done, active_state); |
2522 | 2523 | ||
2523 | session_id2 = kex->session_id; | 2524 | session_id2 = kex->session_id; |
2524 | session_id2_len = kex->session_id_len; | 2525 | session_id2_len = kex->session_id_len; |