diff options
Diffstat (limited to 'kexgexs.c')
-rw-r--r-- | kexgexs.c | 114 |
1 files changed, 31 insertions, 83 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kexgexs.c,v 1.35 2018/10/04 00:04:41 djm Exp $ */ | 1 | /* $OpenBSD: kexgexs.c,v 1.42 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. |
@@ -126,130 +126,78 @@ static int | |||
126 | input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh) | 126 | input_kex_dh_gex_init(int type, u_int32_t seq, struct ssh *ssh) |
127 | { | 127 | { |
128 | struct kex *kex = ssh->kex; | 128 | struct kex *kex = ssh->kex; |
129 | BIGNUM *shared_secret = NULL, *dh_client_pub = NULL; | 129 | BIGNUM *dh_client_pub = NULL; |
130 | const BIGNUM *pub_key, *dh_p, *dh_g; | 130 | const BIGNUM *pub_key, *dh_p, *dh_g; |
131 | struct sshbuf *shared_secret = NULL; | ||
132 | struct sshbuf *server_host_key_blob = NULL; | ||
131 | struct sshkey *server_host_public, *server_host_private; | 133 | struct sshkey *server_host_public, *server_host_private; |
132 | u_char *kbuf = NULL, *signature = NULL, *server_host_key_blob = NULL; | 134 | u_char *signature = NULL; |
133 | u_char hash[SSH_DIGEST_MAX_LENGTH]; | 135 | u_char hash[SSH_DIGEST_MAX_LENGTH]; |
134 | size_t sbloblen, slen; | 136 | size_t slen, hashlen; |
135 | size_t klen = 0, hashlen; | 137 | int r; |
136 | int kout, r; | ||
137 | 138 | ||
138 | if (kex->load_host_public_key == NULL || | 139 | if ((r = kex_load_hostkey(ssh, &server_host_private, |
139 | kex->load_host_private_key == NULL) { | 140 | &server_host_public)) != 0) |
140 | r = SSH_ERR_INVALID_ARGUMENT; | ||
141 | goto out; | ||
142 | } | ||
143 | server_host_public = kex->load_host_public_key(kex->hostkey_type, | ||
144 | kex->hostkey_nid, ssh); | ||
145 | server_host_private = kex->load_host_private_key(kex->hostkey_type, | ||
146 | kex->hostkey_nid, ssh); | ||
147 | if (server_host_public == NULL) { | ||
148 | r = SSH_ERR_NO_HOSTKEY_LOADED; | ||
149 | goto out; | 141 | goto out; |
150 | } | ||
151 | 142 | ||
152 | /* key, cert */ | 143 | /* key, cert */ |
153 | if ((dh_client_pub = BN_new()) == NULL) { | 144 | if ((r = sshpkt_get_bignum2(ssh, &dh_client_pub)) != 0 || |
154 | r = SSH_ERR_ALLOC_FAIL; | ||
155 | goto out; | ||
156 | } | ||
157 | if ((r = sshpkt_get_bignum2(ssh, dh_client_pub)) != 0 || | ||
158 | (r = sshpkt_get_end(ssh)) != 0) | 145 | (r = sshpkt_get_end(ssh)) != 0) |
159 | goto out; | 146 | goto out; |
160 | 147 | if ((shared_secret = sshbuf_new()) == NULL) { | |
161 | DH_get0_key(kex->dh, &pub_key, NULL); | ||
162 | DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); | ||
163 | |||
164 | #ifdef DEBUG_KEXDH | ||
165 | fprintf(stderr, "dh_client_pub= "); | ||
166 | BN_print_fp(stderr, dh_client_pub); | ||
167 | fprintf(stderr, "\n"); | ||
168 | debug("bits %d", BN_num_bits(dh_client_pub)); | ||
169 | DHparams_print_fp(stderr, kex->dh); | ||
170 | fprintf(stderr, "pub= "); | ||
171 | BN_print_fp(stderr, pub_key); | ||
172 | fprintf(stderr, "\n"); | ||
173 | #endif | ||
174 | if (!dh_pub_is_valid(kex->dh, dh_client_pub)) { | ||
175 | sshpkt_disconnect(ssh, "bad client public DH value"); | ||
176 | r = SSH_ERR_MESSAGE_INCOMPLETE; | ||
177 | goto out; | ||
178 | } | ||
179 | |||
180 | klen = DH_size(kex->dh); | ||
181 | if ((kbuf = malloc(klen)) == NULL || | ||
182 | (shared_secret = BN_new()) == NULL) { | ||
183 | r = SSH_ERR_ALLOC_FAIL; | 148 | r = SSH_ERR_ALLOC_FAIL; |
184 | goto out; | 149 | goto out; |
185 | } | 150 | } |
186 | if ((kout = DH_compute_key(kbuf, dh_client_pub, kex->dh)) < 0 || | 151 | if ((r = kex_dh_compute_key(kex, dh_client_pub, shared_secret)) != 0) |
187 | BN_bin2bn(kbuf, kout, shared_secret) == NULL) { | 152 | goto out; |
188 | r = SSH_ERR_LIBCRYPTO_ERROR; | 153 | if ((server_host_key_blob = sshbuf_new()) == NULL) { |
154 | r = SSH_ERR_ALLOC_FAIL; | ||
189 | goto out; | 155 | goto out; |
190 | } | 156 | } |
191 | #ifdef DEBUG_KEXDH | 157 | if ((r = sshkey_putb(server_host_public, server_host_key_blob)) != 0) |
192 | dump_digest("shared secret", kbuf, kout); | ||
193 | #endif | ||
194 | if ((r = sshkey_to_blob(server_host_public, &server_host_key_blob, | ||
195 | &sbloblen)) != 0) | ||
196 | goto out; | 158 | goto out; |
159 | |||
197 | /* calc H */ | 160 | /* calc H */ |
161 | DH_get0_key(kex->dh, &pub_key, NULL); | ||
162 | DH_get0_pqg(kex->dh, &dh_p, NULL, &dh_g); | ||
198 | hashlen = sizeof(hash); | 163 | hashlen = sizeof(hash); |
199 | if ((r = kexgex_hash( | 164 | if ((r = kexgex_hash( |
200 | kex->hash_alg, | 165 | kex->hash_alg, |
201 | kex->client_version_string, | 166 | kex->client_version, |
202 | kex->server_version_string, | 167 | kex->server_version, |
203 | sshbuf_ptr(kex->peer), sshbuf_len(kex->peer), | 168 | kex->peer, |
204 | sshbuf_ptr(kex->my), sshbuf_len(kex->my), | 169 | kex->my, |
205 | server_host_key_blob, sbloblen, | 170 | server_host_key_blob, |
206 | kex->min, kex->nbits, kex->max, | 171 | kex->min, kex->nbits, kex->max, |
207 | dh_p, dh_g, | 172 | dh_p, dh_g, |
208 | dh_client_pub, | 173 | dh_client_pub, |
209 | pub_key, | 174 | pub_key, |
210 | shared_secret, | 175 | sshbuf_ptr(shared_secret), sshbuf_len(shared_secret), |
211 | hash, &hashlen)) != 0) | 176 | hash, &hashlen)) != 0) |
212 | goto out; | 177 | goto out; |
213 | 178 | ||
214 | /* save session id := H */ | ||
215 | if (kex->session_id == NULL) { | ||
216 | kex->session_id_len = hashlen; | ||
217 | kex->session_id = malloc(kex->session_id_len); | ||
218 | if (kex->session_id == NULL) { | ||
219 | r = SSH_ERR_ALLOC_FAIL; | ||
220 | goto out; | ||
221 | } | ||
222 | memcpy(kex->session_id, hash, kex->session_id_len); | ||
223 | } | ||
224 | |||
225 | /* sign H */ | 179 | /* sign H */ |
226 | if ((r = kex->sign(server_host_private, server_host_public, &signature, | 180 | if ((r = kex->sign(ssh, server_host_private, server_host_public, |
227 | &slen, hash, hashlen, kex->hostkey_alg, ssh->compat)) < 0) | 181 | &signature, &slen, hash, hashlen, kex->hostkey_alg)) < 0) |
228 | goto out; | 182 | goto out; |
229 | 183 | ||
230 | /* destroy_sensitive_data(); */ | ||
231 | |||
232 | /* send server hostkey, DH pubkey 'f' and signed H */ | 184 | /* send server hostkey, DH pubkey 'f' and signed H */ |
233 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 || | 185 | if ((r = sshpkt_start(ssh, SSH2_MSG_KEX_DH_GEX_REPLY)) != 0 || |
234 | (r = sshpkt_put_string(ssh, server_host_key_blob, sbloblen)) != 0 || | 186 | (r = sshpkt_put_stringb(ssh, server_host_key_blob)) != 0 || |
235 | (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || /* f */ | 187 | (r = sshpkt_put_bignum2(ssh, pub_key)) != 0 || /* f */ |
236 | (r = sshpkt_put_string(ssh, signature, slen)) != 0 || | 188 | (r = sshpkt_put_string(ssh, signature, slen)) != 0 || |
237 | (r = sshpkt_send(ssh)) != 0) | 189 | (r = sshpkt_send(ssh)) != 0) |
238 | goto out; | 190 | goto out; |
239 | 191 | ||
240 | if ((r = kex_derive_keys_bn(ssh, hash, hashlen, shared_secret)) == 0) | 192 | if ((r = kex_derive_keys(ssh, hash, hashlen, shared_secret)) == 0) |
241 | r = kex_send_newkeys(ssh); | 193 | r = kex_send_newkeys(ssh); |
242 | out: | 194 | out: |
243 | explicit_bzero(hash, sizeof(hash)); | 195 | explicit_bzero(hash, sizeof(hash)); |
244 | DH_free(kex->dh); | 196 | DH_free(kex->dh); |
245 | kex->dh = NULL; | 197 | kex->dh = NULL; |
246 | BN_clear_free(dh_client_pub); | 198 | BN_clear_free(dh_client_pub); |
247 | if (kbuf) { | 199 | sshbuf_free(shared_secret); |
248 | explicit_bzero(kbuf, klen); | 200 | sshbuf_free(server_host_key_blob); |
249 | free(kbuf); | ||
250 | } | ||
251 | BN_clear_free(shared_secret); | ||
252 | free(server_host_key_blob); | ||
253 | free(signature); | 201 | free(signature); |
254 | return r; | 202 | return r; |
255 | } | 203 | } |