diff options
Diffstat (limited to 'kexgexc.c')
-rw-r--r-- | kexgexc.c | 109 |
1 files changed, 29 insertions, 80 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexgexc.c,v 1.27 2018/02/07 02:06:51 jsing Exp $ */ | 1 | /* $OpenBSD: kexgexc.c,v 1.34 2019/01/23 00:30:41 djm 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. |
@@ -100,13 +100,8 @@ input_kex_dh_gex_group(int type, u_int32_t seq, struct ssh *ssh) | |||
100 | 100 | ||
101 | debug("got SSH2_MSG_KEX_DH_GEX_GROUP"); | 101 | debug("got SSH2_MSG_KEX_DH_GEX_GROUP"); |
102 | 102 | ||
103 | if ((p = BN_new()) == NULL || | 103 | if ((r = sshpkt_get_bignum2(ssh, &p)) != 0 || |
104 | (g = BN_new()) == NULL) { | 104 | (r = sshpkt_get_bignum2(ssh, &g)) != 0 || |
105 | r = SSH_ERR_ALLOC_FAIL; | ||
106 | goto out; | ||
107 | } | ||
108 | if ((r = sshpkt_get_bignum2(ssh, p)) != 0 || | ||
109 | (r = sshpkt_get_bignum2(ssh, g)) != 0 || | ||
110 | (r = sshpkt_get_end(ssh)) != 0) | 105 | (r = sshpkt_get_end(ssh)) != 0) |
111 | goto out; | 106 | goto out; |
112 | if ((bits = BN_num_bits(p)) < 0 || | 107 | if ((bits = BN_num_bits(p)) < 0 || |
@@ -148,71 +143,39 @@ static int | |||
148 | input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) | 143 | input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) |
149 | { | 144 | { |
150 | struct kex *kex = ssh->kex; | 145 | struct kex *kex = ssh->kex; |
151 | BIGNUM *dh_server_pub = NULL, *shared_secret = NULL; | 146 | BIGNUM *dh_server_pub = NULL; |
152 | const BIGNUM *pub_key, *dh_p, *dh_g; | 147 | const BIGNUM *pub_key, *dh_p, *dh_g; |
148 | struct sshbuf *shared_secret = NULL; | ||
149 | struct sshbuf *tmp = NULL, *server_host_key_blob = NULL; | ||
153 | struct sshkey *server_host_key = NULL; | 150 | struct sshkey *server_host_key = NULL; |
154 | u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; | 151 | u_char *signature = NULL; |
155 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | 152 | u_char hash[SSH_DIGEST_MAX_LENGTH]; |
156 | size_t klen = 0, slen, sbloblen, hashlen; | 153 | size_t slen, hashlen; |
157 | int kout, r; | 154 | int r; |
158 | 155 | ||
159 | debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); | 156 | debug("got SSH2_MSG_KEX_DH_GEX_REPLY"); |
160 | if (kex->verify_host_key == NULL) { | ||
161 | r = SSH_ERR_INVALID_ARGUMENT; | ||
162 | goto out; | ||
163 | } | ||
164 | /* key, cert */ | 157 | /* key, cert */ |
165 | if ((r = sshpkt_get_string(ssh, &server_host_key_blob, | 158 | if ((r = sshpkt_getb_froms(ssh, &server_host_key_blob)) != 0) |
166 | &sbloblen)) != 0 || | ||
167 | (r = sshkey_from_blob(server_host_key_blob, sbloblen, | ||
168 | &server_host_key)) != 0) | ||
169 | goto out; | 159 | goto out; |
170 | if (server_host_key->type != kex->hostkey_type || | 160 | /* sshkey_fromb() consumes its buffer, so make a copy */ |
171 | (kex->hostkey_type == KEY_ECDSA && | 161 | if ((tmp = sshbuf_fromb(server_host_key_blob)) == NULL) { |
172 | server_host_key->ecdsa_nid != kex->hostkey_nid)) { | ||
173 | r = SSH_ERR_KEY_TYPE_MISMATCH; | ||
174 | goto out; | ||
175 | } | ||
176 | if (kex->verify_host_key(server_host_key, ssh) == -1) { | ||
177 | r = SSH_ERR_SIGNATURE_INVALID; | ||
178 | goto out; | ||
179 | } | ||
180 | /* DH parameter f, server public DH key */ | ||
181 | if ((dh_server_pub = BN_new()) == NULL) { | ||
182 | r = SSH_ERR_ALLOC_FAIL; | 162 | r = SSH_ERR_ALLOC_FAIL; |
183 | goto out; | 163 | goto out; |
184 | } | 164 | } |
185 | /* signed H */ | 165 | if ((r = sshkey_fromb(tmp, &server_host_key)) != 0 || |
186 | if ((r = sshpkt_get_bignum2(ssh, dh_server_pub)) != 0 || | 166 | (r = kex_verify_host_key(ssh, server_host_key)) != 0) |
167 | goto out; | ||
168 | /* DH parameter f, server public DH key, signed H */ | ||
169 | if ((r = sshpkt_get_bignum2(ssh, &dh_server_pub)) != 0 || | ||
187 | (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || | 170 | (r = sshpkt_get_string(ssh, &signature, &slen)) != 0 || |
188 | (r = sshpkt_get_end(ssh)) != 0) | 171 | (r = sshpkt_get_end(ssh)) != 0) |
189 | goto out; | 172 | goto out; |
190 | #ifdef DEBUG_KEXDH | 173 | if ((shared_secret = sshbuf_new()) == NULL) { |
191 | fprintf(stderr, "dh_server_pub= "); | ||
192 | BN_print_fp(stderr, dh_server_pub); | ||
193 | fprintf(stderr, "\n"); | ||
194 | debug("bits %d", BN_num_bits(dh_server_pub)); | ||
195 | #endif | ||
196 | if (!dh_pub_is_valid(kex->dh, dh_server_pub)) { | ||
197 | sshpkt_disconnect(ssh, "bad server public DH value"); | ||
198 | r = SSH_ERR_MESSAGE_INCOMPLETE; | ||
199 | goto out; | ||
200 | } | ||
201 | |||
202 | klen = DH_size(kex->dh); | ||
203 | if ((kbuf = malloc(klen)) == NULL || | ||
204 | (shared_secret = BN_new()) == NULL) { | ||
205 | r = SSH_ERR_ALLOC_FAIL; | 174 | r = SSH_ERR_ALLOC_FAIL; |
206 | goto out; | 175 | goto out; |
207 | } | 176 | } |
208 | if ((kout = DH_compute_key(kbuf, dh_server_pub, kex->dh)) < 0 || | 177 | if ((r = kex_dh_compute_key(kex, dh_server_pub, shared_secret)) != 0) |
209 | BN_bin2bn(kbuf, kout, shared_secret) == NULL) { | ||
210 | r = SSH_ERR_LIBCRYPTO_ERROR; | ||
211 | goto out; | 178 | goto out; |
212 | } | ||
213 | #ifdef DEBUG_KEXDH | ||
214 | dump_digest("shared secret", kbuf, kout); | ||
215 | #endif | ||
216 | if (ssh->compat & SSH_OLD_DHGEX) | 179 | if (ssh->compat & SSH_OLD_DHGEX) |
217 | kex->min = kex->max = -1; | 180 | kex->min = kex->max = -1; |
218 | 181 | ||
@@ -222,16 +185,16 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) | |||
222 | hashlen = sizeof(hash); | 185 | hashlen = sizeof(hash); |
223 | if ((r = kexgex_hash( | 186 | if ((r = kexgex_hash( |
224 | kex->hash_alg, | 187 | kex->hash_alg, |
225 | kex->client_version_string, | 188 | kex->client_version, |
226 | kex->server_version_string, | 189 | kex->server_version, |
227 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), | 190 | kex->my, |
228 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), | 191 | kex->peer, |
229 | server_host_key_blob, sbloblen, | 192 | server_host_key_blob, |
230 | kex->min, kex->nbits, kex->max, | 193 | kex->min, kex->nbits, kex->max, |
231 | dh_p, dh_g, | 194 | dh_p, dh_g, |
232 | pub_key, | 195 | pub_key, |
233 | dh_server_pub, | 196 | dh_server_pub, |
234 | shared_secret, | 197 | sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), |
235 | hash, &hashlen)) != 0) | 198 | hash, &hashlen)) != 0) |
236 | goto out; | 199 | goto out; |
237 | 200 | ||
@@ -239,31 +202,17 @@ input_kex_dh_gex_reply(int type, u_int32_t seq, struct ssh *ssh) | |||
239 | hashlen, kex->hostkey_alg, ssh->compat)) != 0) | 202 | hashlen, kex->hostkey_alg, ssh->compat)) != 0) |
240 | goto out; | 203 | goto out; |
241 | 204 | ||
242 | /* save session id */ | 205 | if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) |
243 | if (kex->session_id == NULL) { | ||
244 | kex->session_id_len = hashlen; | ||
245 | kex->session_id = malloc(kex->session_id_len); | ||
246 | if (kex->session_id == NULL) { | ||
247 | r = SSH_ERR_ALLOC_FAIL; | ||
248 | goto out; | ||
249 | } | ||
250 | memcpy(kex->session_id, hash, kex->session_id_len); | ||
251 | } | ||
252 | |||
253 | if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) | ||
254 | r = kex_send_newkeys(ssh); | 206 | r = kex_send_newkeys(ssh); |
255 | out: | 207 | out: |
256 | explicit_bzero(hash, sizeof(hash)); | 208 | explicit_bzero(hash, sizeof(hash)); |
257 | DH_free(kex->dh); | 209 | DH_free(kex->dh); |
258 | kex->dh = NULL; | 210 | kex->dh = NULL; |
259 | BN_clear_free(dh_server_pub); | 211 | BN_clear_free(dh_server_pub); |
260 | if (kbuf) { | 212 | sshbuf_free(shared_secret); |
261 | explicit_bzero(kbuf, klen); | ||
262 | free(kbuf); | ||
263 | } | ||
264 | BN_clear_free(shared_secret); | ||
265 | sshkey_free(server_host_key); | 213 | sshkey_free(server_host_key); |
266 | free(server_host_key_blob); | 214 | sshbuf_free(tmp); |
215 | sshbuf_free(server_host_key_blob); | ||
267 | free(signature); | 216 | free(signature); |
268 | return r; | 217 | return r; |
269 | } | 218 | } |