diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | dh.c | 21 | ||||
-rw-r--r-- | dh.h | 4 | ||||
-rw-r--r-- | kex.c | 386 | ||||
-rw-r--r-- | kex.h | 58 | ||||
-rw-r--r-- | sshconnect2.c | 409 | ||||
-rw-r--r-- | sshd.c | 359 |
7 files changed, 284 insertions, 959 deletions
@@ -6,6 +6,10 @@ | |||
6 | - stevesk@cvs.openbsd.org 2001/04/03 13:56:11 | 6 | - stevesk@cvs.openbsd.org 2001/04/03 13:56:11 |
7 | [sftp-glob.c ssh-agent.c ssh-keygen.c] | 7 | [sftp-glob.c ssh-agent.c ssh-keygen.c] |
8 | free() -> xfree() | 8 | free() -> xfree() |
9 | - markus@cvs.openbsd.org 2001/04/03 19:53:29 | ||
10 | [dh.c dh.h kex.c kex.h sshconnect2.c sshd.c] | ||
11 | move kex to kex*.c, used dispatch_set() callbacks for kex. should | ||
12 | make rekeying easier. | ||
9 | 13 | ||
10 | 20010403 | 14 | 20010403 |
11 | - OpenBSD CVS Sync | 15 | - OpenBSD CVS Sync |
@@ -4816,4 +4820,4 @@ | |||
4816 | - Wrote replacements for strlcpy and mkdtemp | 4820 | - Wrote replacements for strlcpy and mkdtemp |
4817 | - Released 1.0pre1 | 4821 | - Released 1.0pre1 |
4818 | 4822 | ||
4819 | $Id: ChangeLog,v 1.1049 2001/04/04 01:53:20 mouring Exp $ | 4823 | $Id: ChangeLog,v 1.1050 2001/04/04 01:56:17 mouring Exp $ |
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: dh.c,v 1.11 2001/03/29 21:17:39 markus Exp $"); | 26 | RCSID("$OpenBSD: dh.c,v 1.12 2001/04/03 19:53:29 markus Exp $"); |
27 | 27 | ||
28 | #include "xmalloc.h" | 28 | #include "xmalloc.h" |
29 | 29 | ||
@@ -273,3 +273,22 @@ dh_new_group1(void) | |||
273 | 273 | ||
274 | return (dh_new_group_asc(gen, group1)); | 274 | return (dh_new_group_asc(gen, group1)); |
275 | } | 275 | } |
276 | |||
277 | /* | ||
278 | * Estimates the group order for a Diffie-Hellman group that has an | ||
279 | * attack complexity approximately the same as O(2**bits). Estimate | ||
280 | * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) | ||
281 | */ | ||
282 | |||
283 | int | ||
284 | dh_estimate(int bits) | ||
285 | { | ||
286 | |||
287 | if (bits < 64) | ||
288 | return (512); /* O(2**63) */ | ||
289 | if (bits < 128) | ||
290 | return (1024); /* O(2**86) */ | ||
291 | if (bits < 192) | ||
292 | return (2048); /* O(2**116) */ | ||
293 | return (4096); /* O(2**156) */ | ||
294 | } | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: dh.h,v 1.4 2001/03/29 21:17:39 markus Exp $ */ | 1 | /* $OpenBSD: dh.h,v 1.5 2001/04/03 19:53:29 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Niels Provos. All rights reserved. | 4 | * Copyright (c) 2000 Niels Provos. All rights reserved. |
@@ -40,6 +40,8 @@ DH *dh_new_group1(void); | |||
40 | void dh_gen_key(DH *, int); | 40 | void dh_gen_key(DH *, int); |
41 | int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub); | 41 | int dh_pub_is_valid(DH *dh, BIGNUM *dh_pub); |
42 | 42 | ||
43 | int dh_estimate(int bits); | ||
44 | |||
43 | #define DH_GRP_MIN 1024 | 45 | #define DH_GRP_MIN 1024 |
44 | #define DH_GRP_MAX 8192 | 46 | #define DH_GRP_MAX 8192 |
45 | 47 | ||
@@ -23,12 +23,9 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: kex.c,v 1.25 2001/03/29 21:17:39 markus Exp $"); | 26 | RCSID("$OpenBSD: kex.c,v 1.26 2001/04/03 19:53:29 markus Exp $"); |
27 | 27 | ||
28 | #include <openssl/crypto.h> | 28 | #include <openssl/crypto.h> |
29 | #include <openssl/bio.h> | ||
30 | #include <openssl/bn.h> | ||
31 | #include <openssl/pem.h> | ||
32 | 29 | ||
33 | #include "ssh2.h" | 30 | #include "ssh2.h" |
34 | #include "xmalloc.h" | 31 | #include "xmalloc.h" |
@@ -42,233 +39,169 @@ RCSID("$OpenBSD: kex.c,v 1.25 2001/03/29 21:17:39 markus Exp $"); | |||
42 | #include "log.h" | 39 | #include "log.h" |
43 | #include "mac.h" | 40 | #include "mac.h" |
44 | #include "match.h" | 41 | #include "match.h" |
42 | #include "dispatch.h" | ||
45 | 43 | ||
46 | #define KEX_COOKIE_LEN 16 | 44 | #define KEX_COOKIE_LEN 16 |
47 | 45 | ||
48 | Buffer * | 46 | void kex_kexinit_finish(Kex *kex); |
49 | kex_init(char *myproposal[PROPOSAL_MAX]) | 47 | void kex_choose_conf(Kex *k); |
48 | |||
49 | /* put algorithm proposal into buffer */ | ||
50 | void | ||
51 | kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX]) | ||
50 | { | 52 | { |
51 | int first_kex_packet_follows = 0; | ||
52 | u_char cookie[KEX_COOKIE_LEN]; | ||
53 | u_int32_t rand = 0; | 53 | u_int32_t rand = 0; |
54 | int i; | 54 | int i; |
55 | Buffer *ki = xmalloc(sizeof(*ki)); | 55 | |
56 | buffer_clear(b); | ||
56 | for (i = 0; i < KEX_COOKIE_LEN; i++) { | 57 | for (i = 0; i < KEX_COOKIE_LEN; i++) { |
57 | if (i % 4 == 0) | 58 | if (i % 4 == 0) |
58 | rand = arc4random(); | 59 | rand = arc4random(); |
59 | cookie[i] = rand & 0xff; | 60 | buffer_put_char(b, rand & 0xff); |
60 | rand >>= 8; | 61 | rand >>= 8; |
61 | } | 62 | } |
62 | buffer_init(ki); | ||
63 | buffer_append(ki, (char *)cookie, sizeof cookie); | ||
64 | for (i = 0; i < PROPOSAL_MAX; i++) | 63 | for (i = 0; i < PROPOSAL_MAX; i++) |
65 | buffer_put_cstring(ki, myproposal[i]); | 64 | buffer_put_cstring(b, proposal[i]); |
66 | buffer_put_char(ki, first_kex_packet_follows); | 65 | buffer_put_char(b, 0); /* first_kex_packet_follows */ |
67 | buffer_put_int(ki, 0); /* uint32 reserved */ | 66 | buffer_put_int(b, 0); /* uint32 reserved */ |
68 | return ki; | ||
69 | } | 67 | } |
70 | 68 | ||
71 | /* send kexinit, parse and save reply */ | 69 | /* parse buffer and return algorithm proposal */ |
72 | void | 70 | char ** |
73 | kex_exchange_kexinit( | 71 | kex_buf2prop(Buffer *raw) |
74 | Buffer *my_kexinit, Buffer *peer_kexint, | ||
75 | char *peer_proposal[PROPOSAL_MAX]) | ||
76 | { | 72 | { |
73 | Buffer b; | ||
77 | int i; | 74 | int i; |
78 | char *ptr; | 75 | char **proposal; |
79 | int plen; | ||
80 | 76 | ||
81 | debug("send KEXINIT"); | 77 | proposal = xmalloc(PROPOSAL_MAX * sizeof(char *)); |
82 | packet_start(SSH2_MSG_KEXINIT); | 78 | |
83 | packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit)); | 79 | buffer_init(&b); |
84 | packet_send(); | 80 | buffer_append(&b, buffer_ptr(raw), buffer_len(raw)); |
85 | packet_write_wait(); | ||
86 | debug("done"); | ||
87 | |||
88 | /* | ||
89 | * read and save raw KEXINIT payload in buffer. this is used during | ||
90 | * computation of the session_id and the session keys. | ||
91 | */ | ||
92 | debug("wait KEXINIT"); | ||
93 | packet_read_expect(&plen, SSH2_MSG_KEXINIT); | ||
94 | ptr = packet_get_raw(&plen); | ||
95 | buffer_append(peer_kexint, ptr, plen); | ||
96 | |||
97 | /* parse packet and save algorithm proposal */ | ||
98 | /* skip cookie */ | 81 | /* skip cookie */ |
99 | for (i = 0; i < KEX_COOKIE_LEN; i++) | 82 | for (i = 0; i < KEX_COOKIE_LEN; i++) |
100 | packet_get_char(); | 83 | buffer_get_char(&b); |
101 | /* extract kex init proposal strings */ | 84 | /* extract kex init proposal strings */ |
102 | for (i = 0; i < PROPOSAL_MAX; i++) { | 85 | for (i = 0; i < PROPOSAL_MAX; i++) { |
103 | peer_proposal[i] = packet_get_string(NULL); | 86 | proposal[i] = buffer_get_string(&b,NULL); |
104 | debug("got kexinit: %s", peer_proposal[i]); | 87 | debug2("kex_parse_kexinit: %s", proposal[i]); |
105 | } | 88 | } |
106 | /* first kex follow / reserved */ | 89 | /* first kex follows / reserved */ |
107 | i = packet_get_char(); | 90 | i = buffer_get_char(&b); |
108 | debug("first kex follow: %d ", i); | 91 | debug2("kex_parse_kexinit: first_kex_follows %d ", i); |
109 | i = packet_get_int(); | 92 | i = buffer_get_int(&b); |
110 | debug("reserved: %d ", i); | 93 | debug2("kex_parse_kexinit: reserved %d ", i); |
111 | packet_done(); | 94 | buffer_free(&b); |
112 | debug("done"); | 95 | return proposal; |
113 | } | 96 | } |
114 | 97 | ||
115 | #ifdef DEBUG_KEX | ||
116 | void | 98 | void |
117 | dump_digest(u_char *digest, int len) | 99 | kex_prop_free(char **proposal) |
118 | { | 100 | { |
119 | int i; | 101 | int i; |
120 | for (i = 0; i< len; i++){ | 102 | |
121 | fprintf(stderr, "%02x", digest[i]); | 103 | for (i = 0; i < PROPOSAL_MAX; i++) |
122 | if(i%2!=0) | 104 | xfree(proposal[i]); |
123 | fprintf(stderr, " "); | 105 | xfree(proposal); |
124 | } | ||
125 | fprintf(stderr, "\n"); | ||
126 | } | 106 | } |
127 | #endif | ||
128 | 107 | ||
129 | u_char * | 108 | void |
130 | kex_hash( | 109 | kex_protocol_error(int type, int plen, void *ctxt) |
131 | char *client_version_string, | ||
132 | char *server_version_string, | ||
133 | char *ckexinit, int ckexinitlen, | ||
134 | char *skexinit, int skexinitlen, | ||
135 | char *serverhostkeyblob, int sbloblen, | ||
136 | BIGNUM *client_dh_pub, | ||
137 | BIGNUM *server_dh_pub, | ||
138 | BIGNUM *shared_secret) | ||
139 | { | 110 | { |
140 | Buffer b; | 111 | error("Hm, kex protocol error: type %d plen %d", type, plen); |
141 | static u_char digest[EVP_MAX_MD_SIZE]; | 112 | } |
142 | EVP_MD *evp_md = EVP_sha1(); | ||
143 | EVP_MD_CTX md; | ||
144 | |||
145 | buffer_init(&b); | ||
146 | buffer_put_string(&b, client_version_string, strlen(client_version_string)); | ||
147 | buffer_put_string(&b, server_version_string, strlen(server_version_string)); | ||
148 | |||
149 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | ||
150 | buffer_put_int(&b, ckexinitlen+1); | ||
151 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | ||
152 | buffer_append(&b, ckexinit, ckexinitlen); | ||
153 | buffer_put_int(&b, skexinitlen+1); | ||
154 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | ||
155 | buffer_append(&b, skexinit, skexinitlen); | ||
156 | |||
157 | buffer_put_string(&b, serverhostkeyblob, sbloblen); | ||
158 | buffer_put_bignum2(&b, client_dh_pub); | ||
159 | buffer_put_bignum2(&b, server_dh_pub); | ||
160 | buffer_put_bignum2(&b, shared_secret); | ||
161 | |||
162 | #ifdef DEBUG_KEX | ||
163 | buffer_dump(&b); | ||
164 | #endif | ||
165 | 113 | ||
166 | EVP_DigestInit(&md, evp_md); | 114 | void |
167 | EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); | 115 | kex_send_newkeys(void) |
168 | EVP_DigestFinal(&md, digest, NULL); | 116 | { |
117 | packet_start(SSH2_MSG_NEWKEYS); | ||
118 | packet_send(); | ||
119 | /* packet_write_wait(); */ | ||
120 | debug("SSH2_MSG_NEWKEYS sent"); | ||
121 | } | ||
169 | 122 | ||
170 | buffer_free(&b); | 123 | void |
124 | kex_input_newkeys(int type, int plen, void *ctxt) | ||
125 | { | ||
126 | Kex *kex = ctxt; | ||
127 | int i; | ||
171 | 128 | ||
172 | #ifdef DEBUG_KEX | 129 | debug("SSH2_MSG_NEWKEYS received"); |
173 | dump_digest(digest, evp_md->md_size); | 130 | kex->newkeys = 1; |
174 | #endif | 131 | for (i = 30; i <= 49; i++) |
175 | return digest; | 132 | dispatch_set(i, &kex_protocol_error); |
133 | buffer_clear(&kex->peer); | ||
134 | buffer_clear(&kex->my); | ||
135 | kex->flags &= ~KEX_INIT_SENT; | ||
176 | } | 136 | } |
177 | 137 | ||
178 | u_char * | 138 | void |
179 | kex_hash_gex( | 139 | kex_send_kexinit(Kex *kex) |
180 | char *client_version_string, | ||
181 | char *server_version_string, | ||
182 | char *ckexinit, int ckexinitlen, | ||
183 | char *skexinit, int skexinitlen, | ||
184 | char *serverhostkeyblob, int sbloblen, | ||
185 | int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen, | ||
186 | BIGNUM *client_dh_pub, | ||
187 | BIGNUM *server_dh_pub, | ||
188 | BIGNUM *shared_secret) | ||
189 | { | 140 | { |
190 | Buffer b; | 141 | packet_start(SSH2_MSG_KEXINIT); |
191 | static u_char digest[EVP_MAX_MD_SIZE]; | 142 | packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my)); |
192 | EVP_MD *evp_md = EVP_sha1(); | 143 | packet_send(); |
193 | EVP_MD_CTX md; | 144 | debug("SSH2_MSG_KEXINIT sent"); |
194 | 145 | kex->flags |= KEX_INIT_SENT; | |
195 | buffer_init(&b); | 146 | } |
196 | buffer_put_string(&b, client_version_string, strlen(client_version_string)); | ||
197 | buffer_put_string(&b, server_version_string, strlen(server_version_string)); | ||
198 | |||
199 | /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */ | ||
200 | buffer_put_int(&b, ckexinitlen+1); | ||
201 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | ||
202 | buffer_append(&b, ckexinit, ckexinitlen); | ||
203 | buffer_put_int(&b, skexinitlen+1); | ||
204 | buffer_put_char(&b, SSH2_MSG_KEXINIT); | ||
205 | buffer_append(&b, skexinit, skexinitlen); | ||
206 | |||
207 | buffer_put_string(&b, serverhostkeyblob, sbloblen); | ||
208 | if (min == -1 || max == -1) | ||
209 | buffer_put_int(&b, wantbits); | ||
210 | else { | ||
211 | buffer_put_int(&b, min); | ||
212 | buffer_put_int(&b, wantbits); | ||
213 | buffer_put_int(&b, max); | ||
214 | } | ||
215 | buffer_put_bignum2(&b, prime); | ||
216 | buffer_put_bignum2(&b, gen); | ||
217 | buffer_put_bignum2(&b, client_dh_pub); | ||
218 | buffer_put_bignum2(&b, server_dh_pub); | ||
219 | buffer_put_bignum2(&b, shared_secret); | ||
220 | 147 | ||
221 | #ifdef DEBUG_KEX | 148 | void |
222 | buffer_dump(&b); | 149 | kex_input_kexinit(int type, int plen, void *ctxt) |
223 | #endif | 150 | { |
151 | char *ptr; | ||
152 | int dlen; | ||
153 | Kex *kex = (Kex *)ctxt; | ||
224 | 154 | ||
225 | EVP_DigestInit(&md, evp_md); | 155 | dispatch_set(SSH2_MSG_KEXINIT, &kex_protocol_error); |
226 | EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); | 156 | debug("SSH2_MSG_KEXINIT received"); |
227 | EVP_DigestFinal(&md, digest, NULL); | ||
228 | 157 | ||
229 | buffer_free(&b); | 158 | ptr = packet_get_raw(&dlen); |
159 | buffer_append(&kex->peer, ptr, dlen); | ||
230 | 160 | ||
231 | #ifdef DEBUG_KEX | 161 | kex_kexinit_finish(kex); |
232 | dump_digest(digest, evp_md->md_size); | ||
233 | #endif | ||
234 | return digest; | ||
235 | } | 162 | } |
236 | 163 | ||
237 | u_char * | 164 | Kex * |
238 | derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret) | 165 | kex_start(char *proposal[PROPOSAL_MAX]) |
239 | { | 166 | { |
240 | Buffer b; | 167 | Kex *kex; |
241 | EVP_MD *evp_md = EVP_sha1(); | 168 | int i; |
242 | EVP_MD_CTX md; | ||
243 | char c = id; | ||
244 | int have; | ||
245 | int mdsz = evp_md->md_size; | ||
246 | u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); | ||
247 | |||
248 | buffer_init(&b); | ||
249 | buffer_put_bignum2(&b, shared_secret); | ||
250 | 169 | ||
251 | EVP_DigestInit(&md, evp_md); | 170 | kex = xmalloc(sizeof(*kex)); |
252 | EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */ | 171 | memset(kex, 0, sizeof(*kex)); |
253 | EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */ | 172 | buffer_init(&kex->peer); |
254 | EVP_DigestUpdate(&md, &c, 1); /* key id */ | 173 | buffer_init(&kex->my); |
255 | EVP_DigestUpdate(&md, hash, mdsz); /* session id */ | 174 | kex_prop2buf(&kex->my, proposal); |
256 | EVP_DigestFinal(&md, digest, NULL); | 175 | kex->newkeys = 0; |
176 | |||
177 | kex_send_kexinit(kex); /* we start */ | ||
178 | /* Numbers 30-49 are used for kex packets */ | ||
179 | for (i = 30; i <= 49; i++) | ||
180 | dispatch_set(i, kex_protocol_error); | ||
181 | |||
182 | dispatch_set(SSH2_MSG_KEXINIT, &kex_input_kexinit); | ||
183 | dispatch_set(SSH2_MSG_NEWKEYS, &kex_input_newkeys); | ||
184 | return kex; | ||
185 | } | ||
257 | 186 | ||
258 | /* expand */ | 187 | void |
259 | for (have = mdsz; need > have; have += mdsz) { | 188 | kex_kexinit_finish(Kex *kex) |
260 | EVP_DigestInit(&md, evp_md); | 189 | { |
261 | EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); | 190 | if (!(kex->flags & KEX_INIT_SENT)) |
262 | EVP_DigestUpdate(&md, hash, mdsz); | 191 | kex_send_kexinit(kex); |
263 | EVP_DigestUpdate(&md, digest, have); | 192 | |
264 | EVP_DigestFinal(&md, digest + have, NULL); | 193 | kex_choose_conf(kex); |
194 | |||
195 | switch(kex->kex_type) { | ||
196 | case DH_GRP1_SHA1: | ||
197 | kexdh(kex); | ||
198 | break; | ||
199 | case DH_GEX_SHA1: | ||
200 | kexgex(kex); | ||
201 | break; | ||
202 | default: | ||
203 | fatal("Unsupported key exchange %d", kex->kex_type); | ||
265 | } | 204 | } |
266 | buffer_free(&b); | ||
267 | #ifdef DEBUG_KEX | ||
268 | fprintf(stderr, "Digest '%c'== ", c); | ||
269 | dump_digest(digest, need); | ||
270 | #endif | ||
271 | return digest; | ||
272 | } | 205 | } |
273 | 206 | ||
274 | void | 207 | void |
@@ -340,17 +273,25 @@ choose_hostkeyalg(Kex *k, char *client, char *server) | |||
340 | xfree(hostkeyalg); | 273 | xfree(hostkeyalg); |
341 | } | 274 | } |
342 | 275 | ||
343 | Kex * | 276 | void |
344 | kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server) | 277 | kex_choose_conf(Kex *k) |
345 | { | 278 | { |
279 | char **my, **peer; | ||
280 | char **cprop, **sprop; | ||
346 | int mode; | 281 | int mode; |
347 | int ctos; /* direction: if true client-to-server */ | 282 | int ctos; /* direction: if true client-to-server */ |
348 | int need; | 283 | int need; |
349 | Kex *k; | ||
350 | 284 | ||
351 | k = xmalloc(sizeof(*k)); | 285 | my = kex_buf2prop(&k->my); |
352 | memset(k, 0, sizeof(*k)); | 286 | peer = kex_buf2prop(&k->peer); |
353 | k->server = server; | 287 | |
288 | if (k->server) { | ||
289 | cprop=peer; | ||
290 | sprop=my; | ||
291 | } else { | ||
292 | cprop=my; | ||
293 | sprop=peer; | ||
294 | } | ||
354 | 295 | ||
355 | for (mode = 0; mode < MODE_MAX; mode++) { | 296 | for (mode = 0; mode < MODE_MAX; mode++) { |
356 | int nenc, nmac, ncomp; | 297 | int nenc, nmac, ncomp; |
@@ -381,11 +322,51 @@ kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server | |||
381 | } | 322 | } |
382 | /* XXX need runden? */ | 323 | /* XXX need runden? */ |
383 | k->we_need = need; | 324 | k->we_need = need; |
384 | return k; | 325 | |
326 | kex_prop_free(my); | ||
327 | kex_prop_free(peer); | ||
328 | |||
329 | } | ||
330 | |||
331 | u_char * | ||
332 | derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret) | ||
333 | { | ||
334 | Buffer b; | ||
335 | EVP_MD *evp_md = EVP_sha1(); | ||
336 | EVP_MD_CTX md; | ||
337 | char c = id; | ||
338 | int have; | ||
339 | int mdsz = evp_md->md_size; | ||
340 | u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz); | ||
341 | |||
342 | buffer_init(&b); | ||
343 | buffer_put_bignum2(&b, shared_secret); | ||
344 | |||
345 | EVP_DigestInit(&md, evp_md); | ||
346 | EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */ | ||
347 | EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */ | ||
348 | EVP_DigestUpdate(&md, &c, 1); /* key id */ | ||
349 | EVP_DigestUpdate(&md, hash, mdsz); /* session id */ | ||
350 | EVP_DigestFinal(&md, digest, NULL); | ||
351 | |||
352 | /* expand */ | ||
353 | for (have = mdsz; need > have; have += mdsz) { | ||
354 | EVP_DigestInit(&md, evp_md); | ||
355 | EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); | ||
356 | EVP_DigestUpdate(&md, hash, mdsz); | ||
357 | EVP_DigestUpdate(&md, digest, have); | ||
358 | EVP_DigestFinal(&md, digest + have, NULL); | ||
359 | } | ||
360 | buffer_free(&b); | ||
361 | #ifdef DEBUG_KEX | ||
362 | fprintf(stderr, "key '%c'== ", c); | ||
363 | dump_digest("key", digest, need); | ||
364 | #endif | ||
365 | return digest; | ||
385 | } | 366 | } |
386 | 367 | ||
387 | #define NKEYS 6 | 368 | #define NKEYS 6 |
388 | int | 369 | void |
389 | kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret) | 370 | kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret) |
390 | { | 371 | { |
391 | int i; | 372 | int i; |
@@ -402,5 +383,22 @@ kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret) | |||
402 | k->enc[mode].key = keys[ctos ? 2 : 3]; | 383 | k->enc[mode].key = keys[ctos ? 2 : 3]; |
403 | k->mac[mode].key = keys[ctos ? 4 : 5]; | 384 | k->mac[mode].key = keys[ctos ? 4 : 5]; |
404 | } | 385 | } |
405 | return 0; | ||
406 | } | 386 | } |
387 | |||
388 | #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) | ||
389 | void | ||
390 | dump_digest(char *msg, u_char *digest, int len) | ||
391 | { | ||
392 | int i; | ||
393 | |||
394 | fprintf(stderr, "%s\n", msg); | ||
395 | for (i = 0; i< len; i++){ | ||
396 | fprintf(stderr, "%02x", digest[i]); | ||
397 | if (i%32 == 31) | ||
398 | fprintf(stderr, "\n"); | ||
399 | else if (i%8 == 7) | ||
400 | fprintf(stderr, " "); | ||
401 | } | ||
402 | fprintf(stderr, "\n"); | ||
403 | } | ||
404 | #endif | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: kex.h,v 1.17 2001/03/29 21:17:40 markus Exp $ */ | 1 | /* $OpenBSD: kex.h,v 1.18 2001/04/03 19:53:29 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000 Markus Friedl. All rights reserved. |
@@ -28,6 +28,8 @@ | |||
28 | 28 | ||
29 | #include <openssl/evp.h> | 29 | #include <openssl/evp.h> |
30 | #include "buffer.h" | 30 | #include "buffer.h" |
31 | #include "cipher.h" | ||
32 | #include "key.h" | ||
31 | 33 | ||
32 | #define KEX_DH1 "diffie-hellman-group1-sha1" | 34 | #define KEX_DH1 "diffie-hellman-group1-sha1" |
33 | #define KEX_DHGEX "diffie-hellman-group-exchange-sha1" | 35 | #define KEX_DHGEX "diffie-hellman-group-exchange-sha1" |
@@ -82,6 +84,7 @@ struct Comp { | |||
82 | int enabled; | 84 | int enabled; |
83 | char *name; | 85 | char *name; |
84 | }; | 86 | }; |
87 | #define KEX_INIT_SENT 0x0001 | ||
85 | struct Kex { | 88 | struct Kex { |
86 | Enc enc [MODE_MAX]; | 89 | Enc enc [MODE_MAX]; |
87 | Mac mac [MODE_MAX]; | 90 | Mac mac [MODE_MAX]; |
@@ -91,40 +94,31 @@ struct Kex { | |||
91 | char *name; | 94 | char *name; |
92 | int hostkey_type; | 95 | int hostkey_type; |
93 | int kex_type; | 96 | int kex_type; |
97 | |||
98 | /* used during kex */ | ||
99 | Buffer my; | ||
100 | Buffer peer; | ||
101 | int newkeys; | ||
102 | int flags; | ||
103 | void *state; | ||
104 | char *client_version_string; | ||
105 | char *server_version_string; | ||
106 | |||
107 | int (*check_host_key)(Key *hostkey); | ||
108 | Key *(*load_host_key)(int type); | ||
94 | }; | 109 | }; |
95 | 110 | ||
96 | Buffer *kex_init(char *myproposal[PROPOSAL_MAX]); | 111 | void kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret); |
97 | void | ||
98 | kex_exchange_kexinit( | ||
99 | Buffer *my_kexinit, Buffer *peer_kexint, | ||
100 | char *peer_proposal[PROPOSAL_MAX]); | ||
101 | Kex * | ||
102 | kex_choose_conf(char *cprop[PROPOSAL_MAX], | ||
103 | char *sprop[PROPOSAL_MAX], int server); | ||
104 | int kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret); | ||
105 | void packet_set_kex(Kex *k); | 112 | void packet_set_kex(Kex *k); |
113 | Kex *kex_start(char *proposal[PROPOSAL_MAX]); | ||
114 | void kex_send_newkeys(void); | ||
115 | void kex_protocol_error(int type, int plen, void *ctxt); | ||
106 | 116 | ||
107 | u_char * | 117 | void kexdh(Kex *); |
108 | kex_hash( | 118 | void kexgex(Kex *); |
109 | char *client_version_string, | 119 | |
110 | char *server_version_string, | 120 | #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) |
111 | char *ckexinit, int ckexinitlen, | 121 | void dump_digest(char *msg, u_char *digest, int len); |
112 | char *skexinit, int skexinitlen, | 122 | #endif |
113 | char *serverhostkeyblob, int sbloblen, | ||
114 | BIGNUM *client_dh_pub, | ||
115 | BIGNUM *server_dh_pub, | ||
116 | BIGNUM *shared_secret); | ||
117 | 123 | ||
118 | u_char * | ||
119 | kex_hash_gex( | ||
120 | char *client_version_string, | ||
121 | char *server_version_string, | ||
122 | char *ckexinit, int ckexinitlen, | ||
123 | char *skexinit, int skexinitlen, | ||
124 | char *serverhostkeyblob, int sbloblen, | ||
125 | int min, int wantbits, int max, | ||
126 | BIGNUM *prime, BIGNUM *gen, | ||
127 | BIGNUM *client_dh_pub, | ||
128 | BIGNUM *server_dh_pub, | ||
129 | BIGNUM *shared_secret); | ||
130 | #endif | 124 | #endif |
diff --git a/sshconnect2.c b/sshconnect2.c index 460d614f0..4ed39a23e 100644 --- a/sshconnect2.c +++ b/sshconnect2.c | |||
@@ -23,7 +23,7 @@ | |||
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include "includes.h" | 25 | #include "includes.h" |
26 | RCSID("$OpenBSD: sshconnect2.c,v 1.60 2001/03/29 21:06:21 stevesk Exp $"); | 26 | RCSID("$OpenBSD: sshconnect2.c,v 1.61 2001/04/03 19:53:29 markus Exp $"); |
27 | 27 | ||
28 | #include <openssl/bn.h> | 28 | #include <openssl/bn.h> |
29 | #include <openssl/md5.h> | 29 | #include <openssl/md5.h> |
@@ -47,15 +47,12 @@ RCSID("$OpenBSD: sshconnect2.c,v 1.60 2001/03/29 21:06:21 stevesk Exp $"); | |||
47 | #include "authfile.h" | 47 | #include "authfile.h" |
48 | #include "cli.h" | 48 | #include "cli.h" |
49 | #include "dh.h" | 49 | #include "dh.h" |
50 | #include "dispatch.h" | ||
51 | #include "authfd.h" | 50 | #include "authfd.h" |
52 | #include "log.h" | 51 | #include "log.h" |
53 | #include "readconf.h" | 52 | #include "readconf.h" |
54 | #include "readpass.h" | 53 | #include "readpass.h" |
55 | #include "match.h" | 54 | #include "match.h" |
56 | 55 | #include "dispatch.h" | |
57 | void ssh_dh1_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); | ||
58 | void ssh_dhgex_client(Kex *, char *, struct sockaddr *, Buffer *, Buffer *); | ||
59 | 56 | ||
60 | /* import */ | 57 | /* import */ |
61 | extern char *client_version_string; | 58 | extern char *client_version_string; |
@@ -69,13 +66,24 @@ extern Options options; | |||
69 | u_char *session_id2 = NULL; | 66 | u_char *session_id2 = NULL; |
70 | int session_id2_len = 0; | 67 | int session_id2_len = 0; |
71 | 68 | ||
69 | char *xxx_host; | ||
70 | struct sockaddr *xxx_hostaddr; | ||
71 | |||
72 | int | ||
73 | check_host_key_callback(Key *hostkey) | ||
74 | { | ||
75 | check_host_key(xxx_host, xxx_hostaddr, hostkey, | ||
76 | options.user_hostfile2, options.system_hostfile2); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
72 | void | 80 | void |
73 | ssh_kex2(char *host, struct sockaddr *hostaddr) | 81 | ssh_kex2(char *host, struct sockaddr *hostaddr) |
74 | { | 82 | { |
75 | int i, plen; | ||
76 | Kex *kex; | 83 | Kex *kex; |
77 | Buffer *client_kexinit, *server_kexinit; | 84 | |
78 | char *sprop[PROPOSAL_MAX]; | 85 | xxx_host = host; |
86 | xxx_hostaddr = hostaddr; | ||
79 | 87 | ||
80 | if (options.ciphers == (char *)-1) { | 88 | if (options.ciphers == (char *)-1) { |
81 | log("No valid ciphers for protocol version 2 given, using defaults."); | 89 | log("No valid ciphers for protocol version 2 given, using defaults."); |
@@ -101,46 +109,13 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
101 | myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; | 109 | myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; |
102 | } | 110 | } |
103 | 111 | ||
104 | /* buffers with raw kexinit messages */ | 112 | kex = kex_start(myproposal); |
105 | server_kexinit = xmalloc(sizeof(*server_kexinit)); | 113 | kex->client_version_string=client_version_string; |
106 | buffer_init(server_kexinit); | 114 | kex->server_version_string=server_version_string; |
107 | client_kexinit = kex_init(myproposal); | 115 | kex->check_host_key=&check_host_key_callback; |
108 | |||
109 | /* algorithm negotiation */ | ||
110 | kex_exchange_kexinit(client_kexinit, server_kexinit, sprop); | ||
111 | kex = kex_choose_conf(myproposal, sprop, 0); | ||
112 | for (i = 0; i < PROPOSAL_MAX; i++) | ||
113 | xfree(sprop[i]); | ||
114 | |||
115 | /* server authentication and session key agreement */ | ||
116 | switch(kex->kex_type) { | ||
117 | case DH_GRP1_SHA1: | ||
118 | ssh_dh1_client(kex, host, hostaddr, | ||
119 | client_kexinit, server_kexinit); | ||
120 | break; | ||
121 | case DH_GEX_SHA1: | ||
122 | ssh_dhgex_client(kex, host, hostaddr, client_kexinit, | ||
123 | server_kexinit); | ||
124 | break; | ||
125 | default: | ||
126 | fatal("Unsupported key exchange %d", kex->kex_type); | ||
127 | } | ||
128 | |||
129 | buffer_free(client_kexinit); | ||
130 | buffer_free(server_kexinit); | ||
131 | xfree(client_kexinit); | ||
132 | xfree(server_kexinit); | ||
133 | 116 | ||
134 | debug("Wait SSH2_MSG_NEWKEYS."); | 117 | /* start key exchange */ |
135 | packet_read_expect(&plen, SSH2_MSG_NEWKEYS); | 118 | dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex); |
136 | packet_done(); | ||
137 | debug("GOT SSH2_MSG_NEWKEYS."); | ||
138 | |||
139 | debug("send SSH2_MSG_NEWKEYS."); | ||
140 | packet_start(SSH2_MSG_NEWKEYS); | ||
141 | packet_send(); | ||
142 | packet_write_wait(); | ||
143 | debug("done: send SSH2_MSG_NEWKEYS."); | ||
144 | 119 | ||
145 | #ifdef DEBUG_KEXDH | 120 | #ifdef DEBUG_KEXDH |
146 | /* send 1st encrypted/maced/compressed message */ | 121 | /* send 1st encrypted/maced/compressed message */ |
@@ -149,339 +124,7 @@ ssh_kex2(char *host, struct sockaddr *hostaddr) | |||
149 | packet_send(); | 124 | packet_send(); |
150 | packet_write_wait(); | 125 | packet_write_wait(); |
151 | #endif | 126 | #endif |
152 | debug("done: KEX2."); | 127 | debug("done: ssh_kex2."); |
153 | } | ||
154 | |||
155 | /* diffie-hellman-group1-sha1 */ | ||
156 | |||
157 | void | ||
158 | ssh_dh1_client(Kex *kex, char *host, struct sockaddr *hostaddr, | ||
159 | Buffer *client_kexinit, Buffer *server_kexinit) | ||
160 | { | ||
161 | #ifdef DEBUG_KEXDH | ||
162 | int i; | ||
163 | #endif | ||
164 | int plen, dlen; | ||
165 | u_int klen, kout; | ||
166 | char *signature = NULL; | ||
167 | u_int slen; | ||
168 | char *server_host_key_blob = NULL; | ||
169 | Key *server_host_key; | ||
170 | u_int sbloblen; | ||
171 | DH *dh; | ||
172 | BIGNUM *dh_server_pub = 0; | ||
173 | BIGNUM *shared_secret = 0; | ||
174 | u_char *kbuf; | ||
175 | u_char *hash; | ||
176 | |||
177 | debug("Sending SSH2_MSG_KEXDH_INIT."); | ||
178 | /* generate and send 'e', client DH public key */ | ||
179 | dh = dh_new_group1(); | ||
180 | dh_gen_key(dh, kex->we_need * 8); | ||
181 | packet_start(SSH2_MSG_KEXDH_INIT); | ||
182 | packet_put_bignum2(dh->pub_key); | ||
183 | packet_send(); | ||
184 | packet_write_wait(); | ||
185 | |||
186 | #ifdef DEBUG_KEXDH | ||
187 | fprintf(stderr, "\np= "); | ||
188 | BN_print_fp(stderr, dh->p); | ||
189 | fprintf(stderr, "\ng= "); | ||
190 | BN_print_fp(stderr, dh->g); | ||
191 | fprintf(stderr, "\npub= "); | ||
192 | BN_print_fp(stderr, dh->pub_key); | ||
193 | fprintf(stderr, "\n"); | ||
194 | DHparams_print_fp(stderr, dh); | ||
195 | #endif | ||
196 | |||
197 | debug("Wait SSH2_MSG_KEXDH_REPLY."); | ||
198 | |||
199 | packet_read_expect(&plen, SSH2_MSG_KEXDH_REPLY); | ||
200 | |||
201 | debug("Got SSH2_MSG_KEXDH_REPLY."); | ||
202 | |||
203 | /* key, cert */ | ||
204 | server_host_key_blob = packet_get_string(&sbloblen); | ||
205 | server_host_key = key_from_blob(server_host_key_blob, sbloblen); | ||
206 | if (server_host_key == NULL) | ||
207 | fatal("cannot decode server_host_key_blob"); | ||
208 | |||
209 | check_host_key(host, hostaddr, server_host_key, | ||
210 | options.user_hostfile2, options.system_hostfile2); | ||
211 | |||
212 | /* DH paramter f, server public DH key */ | ||
213 | dh_server_pub = BN_new(); | ||
214 | if (dh_server_pub == NULL) | ||
215 | fatal("dh_server_pub == NULL"); | ||
216 | packet_get_bignum2(dh_server_pub, &dlen); | ||
217 | |||
218 | #ifdef DEBUG_KEXDH | ||
219 | fprintf(stderr, "\ndh_server_pub= "); | ||
220 | BN_print_fp(stderr, dh_server_pub); | ||
221 | fprintf(stderr, "\n"); | ||
222 | debug("bits %d", BN_num_bits(dh_server_pub)); | ||
223 | #endif | ||
224 | |||
225 | /* signed H */ | ||
226 | signature = packet_get_string(&slen); | ||
227 | packet_done(); | ||
228 | |||
229 | if (!dh_pub_is_valid(dh, dh_server_pub)) | ||
230 | packet_disconnect("bad server public DH value"); | ||
231 | |||
232 | klen = DH_size(dh); | ||
233 | kbuf = xmalloc(klen); | ||
234 | kout = DH_compute_key(kbuf, dh_server_pub, dh); | ||
235 | #ifdef DEBUG_KEXDH | ||
236 | debug("shared secret: len %d/%d", klen, kout); | ||
237 | fprintf(stderr, "shared secret == "); | ||
238 | for (i = 0; i< kout; i++) | ||
239 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
240 | fprintf(stderr, "\n"); | ||
241 | #endif | ||
242 | shared_secret = BN_new(); | ||
243 | |||
244 | BN_bin2bn(kbuf, kout, shared_secret); | ||
245 | memset(kbuf, 0, klen); | ||
246 | xfree(kbuf); | ||
247 | |||
248 | /* calc and verify H */ | ||
249 | hash = kex_hash( | ||
250 | client_version_string, | ||
251 | server_version_string, | ||
252 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
253 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
254 | server_host_key_blob, sbloblen, | ||
255 | dh->pub_key, | ||
256 | dh_server_pub, | ||
257 | shared_secret | ||
258 | ); | ||
259 | xfree(server_host_key_blob); | ||
260 | DH_free(dh); | ||
261 | BN_free(dh_server_pub); | ||
262 | #ifdef DEBUG_KEXDH | ||
263 | fprintf(stderr, "hash == "); | ||
264 | for (i = 0; i< 20; i++) | ||
265 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
266 | fprintf(stderr, "\n"); | ||
267 | #endif | ||
268 | if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) | ||
269 | fatal("key_verify failed for server_host_key"); | ||
270 | key_free(server_host_key); | ||
271 | xfree(signature); | ||
272 | |||
273 | kex_derive_keys(kex, hash, shared_secret); | ||
274 | BN_clear_free(shared_secret); | ||
275 | packet_set_kex(kex); | ||
276 | |||
277 | /* save session id */ | ||
278 | session_id2_len = 20; | ||
279 | session_id2 = xmalloc(session_id2_len); | ||
280 | memcpy(session_id2, hash, session_id2_len); | ||
281 | } | ||
282 | |||
283 | /* diffie-hellman-group-exchange-sha1 */ | ||
284 | |||
285 | /* | ||
286 | * Estimates the group order for a Diffie-Hellman group that has an | ||
287 | * attack complexity approximately the same as O(2**bits). Estimate | ||
288 | * with: O(exp(1.9223 * (ln q)^(1/3) (ln ln q)^(2/3))) | ||
289 | */ | ||
290 | |||
291 | int | ||
292 | dh_estimate(int bits) | ||
293 | { | ||
294 | |||
295 | if (bits < 64) | ||
296 | return (512); /* O(2**63) */ | ||
297 | if (bits < 128) | ||
298 | return (1024); /* O(2**86) */ | ||
299 | if (bits < 192) | ||
300 | return (2048); /* O(2**116) */ | ||
301 | return (4096); /* O(2**156) */ | ||
302 | } | ||
303 | |||
304 | void | ||
305 | ssh_dhgex_client(Kex *kex, char *host, struct sockaddr *hostaddr, | ||
306 | Buffer *client_kexinit, Buffer *server_kexinit) | ||
307 | { | ||
308 | #ifdef DEBUG_KEXDH | ||
309 | int i; | ||
310 | #endif | ||
311 | int plen, dlen; | ||
312 | u_int klen, kout; | ||
313 | char *signature = NULL; | ||
314 | u_int slen, nbits, min, max; | ||
315 | char *server_host_key_blob = NULL; | ||
316 | Key *server_host_key; | ||
317 | u_int sbloblen; | ||
318 | DH *dh; | ||
319 | BIGNUM *dh_server_pub = 0; | ||
320 | BIGNUM *shared_secret = 0; | ||
321 | BIGNUM *p = 0, *g = 0; | ||
322 | u_char *kbuf; | ||
323 | u_char *hash; | ||
324 | |||
325 | nbits = dh_estimate(kex->we_need * 8); | ||
326 | |||
327 | if (datafellows & SSH_OLD_DHGEX) { | ||
328 | debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST_OLD."); | ||
329 | |||
330 | /* Old GEX request */ | ||
331 | packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD); | ||
332 | packet_put_int(nbits); | ||
333 | min = DH_GRP_MIN; | ||
334 | max = DH_GRP_MAX; | ||
335 | } else { | ||
336 | debug("Sending SSH2_MSG_KEX_DH_GEX_REQUEST."); | ||
337 | |||
338 | /* New GEX request */ | ||
339 | min = DH_GRP_MIN; | ||
340 | max = DH_GRP_MAX; | ||
341 | |||
342 | packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST); | ||
343 | packet_put_int(min); | ||
344 | packet_put_int(nbits); | ||
345 | packet_put_int(max); | ||
346 | } | ||
347 | packet_send(); | ||
348 | packet_write_wait(); | ||
349 | |||
350 | #ifdef DEBUG_KEXDH | ||
351 | fprintf(stderr, "\nmin = %d, nbits = %d, max = %d", min, nbits, max); | ||
352 | #endif | ||
353 | |||
354 | debug("Wait SSH2_MSG_KEX_DH_GEX_GROUP."); | ||
355 | |||
356 | packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_GROUP); | ||
357 | |||
358 | debug("Got SSH2_MSG_KEX_DH_GEX_GROUP."); | ||
359 | |||
360 | if ((p = BN_new()) == NULL) | ||
361 | fatal("BN_new"); | ||
362 | packet_get_bignum2(p, &dlen); | ||
363 | if ((g = BN_new()) == NULL) | ||
364 | fatal("BN_new"); | ||
365 | packet_get_bignum2(g, &dlen); | ||
366 | |||
367 | if (BN_num_bits(p) < min || BN_num_bits(p) > max) | ||
368 | fatal("DH_GEX group out of range: %d !< %d !< %d", | ||
369 | min, BN_num_bits(p), max); | ||
370 | |||
371 | dh = dh_new_group(g, p); | ||
372 | |||
373 | dh_gen_key(dh, kex->we_need * 8); | ||
374 | |||
375 | #ifdef DEBUG_KEXDH | ||
376 | fprintf(stderr, "\np= "); | ||
377 | BN_print_fp(stderr, dh->p); | ||
378 | fprintf(stderr, "\ng= "); | ||
379 | BN_print_fp(stderr, dh->g); | ||
380 | fprintf(stderr, "\npub= "); | ||
381 | BN_print_fp(stderr, dh->pub_key); | ||
382 | fprintf(stderr, "\n"); | ||
383 | DHparams_print_fp(stderr, dh); | ||
384 | #endif | ||
385 | |||
386 | debug("Sending SSH2_MSG_KEX_DH_GEX_INIT."); | ||
387 | /* generate and send 'e', client DH public key */ | ||
388 | packet_start(SSH2_MSG_KEX_DH_GEX_INIT); | ||
389 | packet_put_bignum2(dh->pub_key); | ||
390 | packet_send(); | ||
391 | packet_write_wait(); | ||
392 | |||
393 | debug("Wait SSH2_MSG_KEX_DH_GEX_REPLY."); | ||
394 | |||
395 | packet_read_expect(&plen, SSH2_MSG_KEX_DH_GEX_REPLY); | ||
396 | |||
397 | debug("Got SSH2_MSG_KEXDH_REPLY."); | ||
398 | |||
399 | /* key, cert */ | ||
400 | server_host_key_blob = packet_get_string(&sbloblen); | ||
401 | server_host_key = key_from_blob(server_host_key_blob, sbloblen); | ||
402 | if (server_host_key == NULL) | ||
403 | fatal("cannot decode server_host_key_blob"); | ||
404 | |||
405 | check_host_key(host, hostaddr, server_host_key, | ||
406 | options.user_hostfile2, options.system_hostfile2); | ||
407 | |||
408 | /* DH paramter f, server public DH key */ | ||
409 | dh_server_pub = BN_new(); | ||
410 | if (dh_server_pub == NULL) | ||
411 | fatal("dh_server_pub == NULL"); | ||
412 | packet_get_bignum2(dh_server_pub, &dlen); | ||
413 | |||
414 | #ifdef DEBUG_KEXDH | ||
415 | fprintf(stderr, "\ndh_server_pub= "); | ||
416 | BN_print_fp(stderr, dh_server_pub); | ||
417 | fprintf(stderr, "\n"); | ||
418 | debug("bits %d", BN_num_bits(dh_server_pub)); | ||
419 | #endif | ||
420 | |||
421 | /* signed H */ | ||
422 | signature = packet_get_string(&slen); | ||
423 | packet_done(); | ||
424 | |||
425 | if (!dh_pub_is_valid(dh, dh_server_pub)) | ||
426 | packet_disconnect("bad server public DH value"); | ||
427 | |||
428 | klen = DH_size(dh); | ||
429 | kbuf = xmalloc(klen); | ||
430 | kout = DH_compute_key(kbuf, dh_server_pub, dh); | ||
431 | #ifdef DEBUG_KEXDH | ||
432 | debug("shared secret: len %d/%d", klen, kout); | ||
433 | fprintf(stderr, "shared secret == "); | ||
434 | for (i = 0; i< kout; i++) | ||
435 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
436 | fprintf(stderr, "\n"); | ||
437 | #endif | ||
438 | shared_secret = BN_new(); | ||
439 | |||
440 | BN_bin2bn(kbuf, kout, shared_secret); | ||
441 | memset(kbuf, 0, klen); | ||
442 | xfree(kbuf); | ||
443 | |||
444 | if (datafellows & SSH_OLD_DHGEX) { | ||
445 | /* These values are not included in the hash */ | ||
446 | min = -1; | ||
447 | max = -1; | ||
448 | } | ||
449 | |||
450 | /* calc and verify H */ | ||
451 | hash = kex_hash_gex( | ||
452 | client_version_string, | ||
453 | server_version_string, | ||
454 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
455 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
456 | server_host_key_blob, sbloblen, | ||
457 | min, nbits, max, | ||
458 | dh->p, dh->g, | ||
459 | dh->pub_key, | ||
460 | dh_server_pub, | ||
461 | shared_secret | ||
462 | ); | ||
463 | xfree(server_host_key_blob); | ||
464 | DH_free(dh); | ||
465 | BN_free(dh_server_pub); | ||
466 | #ifdef DEBUG_KEXDH | ||
467 | fprintf(stderr, "hash == "); | ||
468 | for (i = 0; i< 20; i++) | ||
469 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
470 | fprintf(stderr, "\n"); | ||
471 | #endif | ||
472 | if (key_verify(server_host_key, (u_char *)signature, slen, hash, 20) != 1) | ||
473 | fatal("key_verify failed for server_host_key"); | ||
474 | key_free(server_host_key); | ||
475 | xfree(signature); | ||
476 | |||
477 | kex_derive_keys(kex, hash, shared_secret); | ||
478 | BN_clear_free(shared_secret); | ||
479 | packet_set_kex(kex); | ||
480 | |||
481 | /* save session id */ | ||
482 | session_id2_len = 20; | ||
483 | session_id2 = xmalloc(session_id2_len); | ||
484 | memcpy(session_id2, hash, session_id2_len); | ||
485 | } | 128 | } |
486 | 129 | ||
487 | /* | 130 | /* |
@@ -563,6 +206,7 @@ ssh_userauth2(const char *server_user, char *host) | |||
563 | Authctxt authctxt; | 206 | Authctxt authctxt; |
564 | int type; | 207 | int type; |
565 | int plen; | 208 | int plen; |
209 | int i; | ||
566 | 210 | ||
567 | if (options.challenge_reponse_authentication) | 211 | if (options.challenge_reponse_authentication) |
568 | options.kbd_interactive_authentication = 1; | 212 | options.kbd_interactive_authentication = 1; |
@@ -603,7 +247,10 @@ ssh_userauth2(const char *server_user, char *host) | |||
603 | /* initial userauth request */ | 247 | /* initial userauth request */ |
604 | userauth_none(&authctxt); | 248 | userauth_none(&authctxt); |
605 | 249 | ||
606 | dispatch_init(&input_userauth_error); | 250 | //dispatch_init(&input_userauth_error); |
251 | for (i = 50; i <= 254; i++) { | ||
252 | dispatch_set(i, &input_userauth_error); | ||
253 | } | ||
607 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); | 254 | dispatch_set(SSH2_MSG_USERAUTH_SUCCESS, &input_userauth_success); |
608 | dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); | 255 | dispatch_set(SSH2_MSG_USERAUTH_FAILURE, &input_userauth_failure); |
609 | dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); | 256 | dispatch_set(SSH2_MSG_USERAUTH_BANNER, &input_userauth_banner); |
@@ -40,7 +40,7 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | RCSID("$OpenBSD: sshd.c,v 1.185 2001/03/29 23:42:01 djm Exp $"); | 43 | RCSID("$OpenBSD: sshd.c,v 1.186 2001/04/03 19:53:29 markus Exp $"); |
44 | 44 | ||
45 | #include <openssl/dh.h> | 45 | #include <openssl/dh.h> |
46 | #include <openssl/bn.h> | 46 | #include <openssl/bn.h> |
@@ -70,6 +70,7 @@ RCSID("$OpenBSD: sshd.c,v 1.185 2001/03/29 23:42:01 djm Exp $"); | |||
70 | #include "canohost.h" | 70 | #include "canohost.h" |
71 | #include "auth.h" | 71 | #include "auth.h" |
72 | #include "misc.h" | 72 | #include "misc.h" |
73 | #include "dispatch.h" | ||
73 | 74 | ||
74 | #ifdef LIBWRAP | 75 | #ifdef LIBWRAP |
75 | #include <tcpd.h> | 76 | #include <tcpd.h> |
@@ -1407,14 +1408,7 @@ do_ssh1_kex(void) | |||
1407 | void | 1408 | void |
1408 | do_ssh2_kex(void) | 1409 | do_ssh2_kex(void) |
1409 | { | 1410 | { |
1410 | Buffer *server_kexinit; | ||
1411 | Buffer *client_kexinit; | ||
1412 | int payload_len; | ||
1413 | int i; | ||
1414 | Kex *kex; | 1411 | Kex *kex; |
1415 | char *cprop[PROPOSAL_MAX]; | ||
1416 | |||
1417 | /* KEXINIT */ | ||
1418 | 1412 | ||
1419 | if (options.ciphers != NULL) { | 1413 | if (options.ciphers != NULL) { |
1420 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = | 1414 | myproposal[PROPOSAL_ENC_ALGS_CTOS] = |
@@ -1431,36 +1425,14 @@ do_ssh2_kex(void) | |||
1431 | } | 1425 | } |
1432 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); | 1426 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); |
1433 | 1427 | ||
1434 | server_kexinit = kex_init(myproposal); | 1428 | kex = kex_start(myproposal); |
1435 | client_kexinit = xmalloc(sizeof(*client_kexinit)); | 1429 | kex->server = 1; |
1436 | buffer_init(client_kexinit); | 1430 | kex->client_version_string=client_version_string; |
1437 | 1431 | kex->server_version_string=server_version_string; | |
1438 | /* algorithm negotiation */ | 1432 | kex->load_host_key=&get_hostkey_by_type; |
1439 | kex_exchange_kexinit(server_kexinit, client_kexinit, cprop); | ||
1440 | kex = kex_choose_conf(cprop, myproposal, 1); | ||
1441 | for (i = 0; i < PROPOSAL_MAX; i++) | ||
1442 | xfree(cprop[i]); | ||
1443 | |||
1444 | switch (kex->kex_type) { | ||
1445 | case DH_GRP1_SHA1: | ||
1446 | ssh_dh1_server(kex, client_kexinit, server_kexinit); | ||
1447 | break; | ||
1448 | case DH_GEX_SHA1: | ||
1449 | ssh_dhgex_server(kex, client_kexinit, server_kexinit); | ||
1450 | break; | ||
1451 | default: | ||
1452 | fatal("Unsupported key exchange %d", kex->kex_type); | ||
1453 | } | ||
1454 | |||
1455 | debug("send SSH2_MSG_NEWKEYS."); | ||
1456 | packet_start(SSH2_MSG_NEWKEYS); | ||
1457 | packet_send(); | ||
1458 | packet_write_wait(); | ||
1459 | debug("done: send SSH2_MSG_NEWKEYS."); | ||
1460 | 1433 | ||
1461 | debug("Wait SSH2_MSG_NEWKEYS."); | 1434 | /* start key exchange */ |
1462 | packet_read_expect(&payload_len, SSH2_MSG_NEWKEYS); | 1435 | dispatch_run(DISPATCH_BLOCK, &kex->newkeys, kex); |
1463 | debug("GOT SSH2_MSG_NEWKEYS."); | ||
1464 | 1436 | ||
1465 | #ifdef DEBUG_KEXDH | 1437 | #ifdef DEBUG_KEXDH |
1466 | /* send 1st encrypted/maced/compressed message */ | 1438 | /* send 1st encrypted/maced/compressed message */ |
@@ -1469,316 +1441,5 @@ do_ssh2_kex(void) | |||
1469 | packet_send(); | 1441 | packet_send(); |
1470 | packet_write_wait(); | 1442 | packet_write_wait(); |
1471 | #endif | 1443 | #endif |
1472 | 1444 | debug("KEX done"); | |
1473 | debug("done: KEX2."); | ||
1474 | } | ||
1475 | |||
1476 | /* | ||
1477 | * SSH2 key exchange | ||
1478 | */ | ||
1479 | |||
1480 | /* diffie-hellman-group1-sha1 */ | ||
1481 | |||
1482 | void | ||
1483 | ssh_dh1_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) | ||
1484 | { | ||
1485 | #ifdef DEBUG_KEXDH | ||
1486 | int i; | ||
1487 | #endif | ||
1488 | int payload_len, dlen; | ||
1489 | int slen; | ||
1490 | u_char *signature = NULL; | ||
1491 | u_char *server_host_key_blob = NULL; | ||
1492 | u_int sbloblen; | ||
1493 | u_int klen, kout; | ||
1494 | u_char *kbuf; | ||
1495 | u_char *hash; | ||
1496 | BIGNUM *shared_secret = 0; | ||
1497 | DH *dh; | ||
1498 | BIGNUM *dh_client_pub = 0; | ||
1499 | Key *hostkey; | ||
1500 | |||
1501 | hostkey = get_hostkey_by_type(kex->hostkey_type); | ||
1502 | if (hostkey == NULL) | ||
1503 | fatal("Unsupported hostkey type %d", kex->hostkey_type); | ||
1504 | |||
1505 | /* KEXDH */ | ||
1506 | /* generate DH key */ | ||
1507 | dh = dh_new_group1(); /* XXX depends on 'kex' */ | ||
1508 | dh_gen_key(dh, kex->we_need * 8); | ||
1509 | |||
1510 | debug("Wait SSH2_MSG_KEXDH_INIT."); | ||
1511 | packet_read_expect(&payload_len, SSH2_MSG_KEXDH_INIT); | ||
1512 | |||
1513 | /* key, cert */ | ||
1514 | dh_client_pub = BN_new(); | ||
1515 | if (dh_client_pub == NULL) | ||
1516 | fatal("dh_client_pub == NULL"); | ||
1517 | packet_get_bignum2(dh_client_pub, &dlen); | ||
1518 | |||
1519 | #ifdef DEBUG_KEXDH | ||
1520 | fprintf(stderr, "\ndh_client_pub= "); | ||
1521 | BN_print_fp(stderr, dh_client_pub); | ||
1522 | fprintf(stderr, "\n"); | ||
1523 | debug("bits %d", BN_num_bits(dh_client_pub)); | ||
1524 | #endif | ||
1525 | |||
1526 | #ifdef DEBUG_KEXDH | ||
1527 | fprintf(stderr, "\np= "); | ||
1528 | BN_print_fp(stderr, dh->p); | ||
1529 | fprintf(stderr, "\ng= "); | ||
1530 | bn_print(dh->g); | ||
1531 | fprintf(stderr, "\npub= "); | ||
1532 | BN_print_fp(stderr, dh->pub_key); | ||
1533 | fprintf(stderr, "\n"); | ||
1534 | DHparams_print_fp(stderr, dh); | ||
1535 | #endif | ||
1536 | if (!dh_pub_is_valid(dh, dh_client_pub)) | ||
1537 | packet_disconnect("bad client public DH value"); | ||
1538 | |||
1539 | klen = DH_size(dh); | ||
1540 | kbuf = xmalloc(klen); | ||
1541 | kout = DH_compute_key(kbuf, dh_client_pub, dh); | ||
1542 | |||
1543 | #ifdef DEBUG_KEXDH | ||
1544 | debug("shared secret: len %d/%d", klen, kout); | ||
1545 | fprintf(stderr, "shared secret == "); | ||
1546 | for (i = 0; i< kout; i++) | ||
1547 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
1548 | fprintf(stderr, "\n"); | ||
1549 | #endif | ||
1550 | shared_secret = BN_new(); | ||
1551 | |||
1552 | BN_bin2bn(kbuf, kout, shared_secret); | ||
1553 | memset(kbuf, 0, klen); | ||
1554 | xfree(kbuf); | ||
1555 | |||
1556 | /* XXX precompute? */ | ||
1557 | key_to_blob(hostkey, &server_host_key_blob, &sbloblen); | ||
1558 | |||
1559 | /* calc H */ /* XXX depends on 'kex' */ | ||
1560 | hash = kex_hash( | ||
1561 | client_version_string, | ||
1562 | server_version_string, | ||
1563 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
1564 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
1565 | (char *)server_host_key_blob, sbloblen, | ||
1566 | dh_client_pub, | ||
1567 | dh->pub_key, | ||
1568 | shared_secret | ||
1569 | ); | ||
1570 | buffer_free(client_kexinit); | ||
1571 | buffer_free(server_kexinit); | ||
1572 | xfree(client_kexinit); | ||
1573 | xfree(server_kexinit); | ||
1574 | BN_free(dh_client_pub); | ||
1575 | #ifdef DEBUG_KEXDH | ||
1576 | fprintf(stderr, "hash == "); | ||
1577 | for (i = 0; i< 20; i++) | ||
1578 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
1579 | fprintf(stderr, "\n"); | ||
1580 | #endif | ||
1581 | /* save session id := H */ | ||
1582 | /* XXX hashlen depends on KEX */ | ||
1583 | session_id2_len = 20; | ||
1584 | session_id2 = xmalloc(session_id2_len); | ||
1585 | memcpy(session_id2, hash, session_id2_len); | ||
1586 | |||
1587 | /* sign H */ | ||
1588 | /* XXX hashlen depends on KEX */ | ||
1589 | key_sign(hostkey, &signature, &slen, hash, 20); | ||
1590 | |||
1591 | destroy_sensitive_data(); | ||
1592 | |||
1593 | /* send server hostkey, DH pubkey 'f' and singed H */ | ||
1594 | packet_start(SSH2_MSG_KEXDH_REPLY); | ||
1595 | packet_put_string((char *)server_host_key_blob, sbloblen); | ||
1596 | packet_put_bignum2(dh->pub_key); /* f */ | ||
1597 | packet_put_string((char *)signature, slen); | ||
1598 | packet_send(); | ||
1599 | xfree(signature); | ||
1600 | xfree(server_host_key_blob); | ||
1601 | packet_write_wait(); | ||
1602 | |||
1603 | kex_derive_keys(kex, hash, shared_secret); | ||
1604 | BN_clear_free(shared_secret); | ||
1605 | packet_set_kex(kex); | ||
1606 | |||
1607 | /* have keys, free DH */ | ||
1608 | DH_free(dh); | ||
1609 | } | ||
1610 | |||
1611 | /* diffie-hellman-group-exchange-sha1 */ | ||
1612 | |||
1613 | void | ||
1614 | ssh_dhgex_server(Kex *kex, Buffer *client_kexinit, Buffer *server_kexinit) | ||
1615 | { | ||
1616 | #ifdef DEBUG_KEXDH | ||
1617 | int i; | ||
1618 | #endif | ||
1619 | int payload_len, dlen; | ||
1620 | int slen, nbits, type, min, max; | ||
1621 | u_char *signature = NULL; | ||
1622 | u_char *server_host_key_blob = NULL; | ||
1623 | u_int sbloblen; | ||
1624 | u_int klen, kout; | ||
1625 | u_char *kbuf; | ||
1626 | u_char *hash; | ||
1627 | BIGNUM *shared_secret = 0; | ||
1628 | DH *dh; | ||
1629 | BIGNUM *dh_client_pub = 0; | ||
1630 | Key *hostkey; | ||
1631 | |||
1632 | hostkey = get_hostkey_by_type(kex->hostkey_type); | ||
1633 | if (hostkey == NULL) | ||
1634 | fatal("Unsupported hostkey type %d", kex->hostkey_type); | ||
1635 | |||
1636 | /* KEXDHGEX */ | ||
1637 | debug("Wait SSH2_MSG_KEX_DH_GEX_REQUEST."); | ||
1638 | type = packet_read(&payload_len); | ||
1639 | if (type != SSH2_MSG_KEX_DH_GEX_REQUEST_OLD && | ||
1640 | type != SSH2_MSG_KEX_DH_GEX_REQUEST) | ||
1641 | packet_disconnect("Protocol error: expected type %d or %d, got %d", | ||
1642 | SSH2_MSG_KEX_DH_GEX_REQUEST_OLD, | ||
1643 | SSH2_MSG_KEX_DH_GEX_REQUEST, | ||
1644 | type); | ||
1645 | if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) { | ||
1646 | nbits = packet_get_int(); | ||
1647 | min = DH_GRP_MIN; | ||
1648 | max = DH_GRP_MAX; | ||
1649 | } else { | ||
1650 | min = packet_get_int(); | ||
1651 | nbits = packet_get_int(); | ||
1652 | max = packet_get_int(); | ||
1653 | |||
1654 | min = MAX(DH_GRP_MIN, min); | ||
1655 | max = MIN(DH_GRP_MAX, max); | ||
1656 | } | ||
1657 | |||
1658 | if (max < min || nbits < min || max < nbits) | ||
1659 | fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d", | ||
1660 | min, nbits, max); | ||
1661 | |||
1662 | dh = choose_dh(min, nbits, max); | ||
1663 | if (dh == NULL) | ||
1664 | packet_disconnect("Protocol error: no matching DH grp found"); | ||
1665 | |||
1666 | debug("Sending SSH2_MSG_KEX_DH_GEX_GROUP."); | ||
1667 | packet_start(SSH2_MSG_KEX_DH_GEX_GROUP); | ||
1668 | packet_put_bignum2(dh->p); | ||
1669 | packet_put_bignum2(dh->g); | ||
1670 | packet_send(); | ||
1671 | packet_write_wait(); | ||
1672 | |||
1673 | /* Compute our exchange value in parallel with the client */ | ||
1674 | |||
1675 | dh_gen_key(dh, kex->we_need * 8); | ||
1676 | |||
1677 | debug("Wait SSH2_MSG_KEX_DH_GEX_INIT."); | ||
1678 | packet_read_expect(&payload_len, SSH2_MSG_KEX_DH_GEX_INIT); | ||
1679 | |||
1680 | /* key, cert */ | ||
1681 | dh_client_pub = BN_new(); | ||
1682 | if (dh_client_pub == NULL) | ||
1683 | fatal("dh_client_pub == NULL"); | ||
1684 | packet_get_bignum2(dh_client_pub, &dlen); | ||
1685 | |||
1686 | #ifdef DEBUG_KEXDH | ||
1687 | fprintf(stderr, "\ndh_client_pub= "); | ||
1688 | BN_print_fp(stderr, dh_client_pub); | ||
1689 | fprintf(stderr, "\n"); | ||
1690 | debug("bits %d", BN_num_bits(dh_client_pub)); | ||
1691 | #endif | ||
1692 | |||
1693 | #ifdef DEBUG_KEXDH | ||
1694 | fprintf(stderr, "\np= "); | ||
1695 | BN_print_fp(stderr, dh->p); | ||
1696 | fprintf(stderr, "\ng= "); | ||
1697 | bn_print(dh->g); | ||
1698 | fprintf(stderr, "\npub= "); | ||
1699 | BN_print_fp(stderr, dh->pub_key); | ||
1700 | fprintf(stderr, "\n"); | ||
1701 | DHparams_print_fp(stderr, dh); | ||
1702 | #endif | ||
1703 | if (!dh_pub_is_valid(dh, dh_client_pub)) | ||
1704 | packet_disconnect("bad client public DH value"); | ||
1705 | |||
1706 | klen = DH_size(dh); | ||
1707 | kbuf = xmalloc(klen); | ||
1708 | kout = DH_compute_key(kbuf, dh_client_pub, dh); | ||
1709 | |||
1710 | #ifdef DEBUG_KEXDH | ||
1711 | debug("shared secret: len %d/%d", klen, kout); | ||
1712 | fprintf(stderr, "shared secret == "); | ||
1713 | for (i = 0; i< kout; i++) | ||
1714 | fprintf(stderr, "%02x", (kbuf[i])&0xff); | ||
1715 | fprintf(stderr, "\n"); | ||
1716 | #endif | ||
1717 | shared_secret = BN_new(); | ||
1718 | |||
1719 | BN_bin2bn(kbuf, kout, shared_secret); | ||
1720 | memset(kbuf, 0, klen); | ||
1721 | xfree(kbuf); | ||
1722 | |||
1723 | /* XXX precompute? */ | ||
1724 | key_to_blob(hostkey, &server_host_key_blob, &sbloblen); | ||
1725 | |||
1726 | if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD) { | ||
1727 | /* These values are not included in the hash */ | ||
1728 | min = -1; | ||
1729 | max = -1; | ||
1730 | } | ||
1731 | |||
1732 | /* calc H */ /* XXX depends on 'kex' */ | ||
1733 | hash = kex_hash_gex( | ||
1734 | client_version_string, | ||
1735 | server_version_string, | ||
1736 | buffer_ptr(client_kexinit), buffer_len(client_kexinit), | ||
1737 | buffer_ptr(server_kexinit), buffer_len(server_kexinit), | ||
1738 | (char *)server_host_key_blob, sbloblen, | ||
1739 | min, nbits, max, | ||
1740 | dh->p, dh->g, | ||
1741 | dh_client_pub, | ||
1742 | dh->pub_key, | ||
1743 | shared_secret | ||
1744 | ); | ||
1745 | buffer_free(client_kexinit); | ||
1746 | buffer_free(server_kexinit); | ||
1747 | xfree(client_kexinit); | ||
1748 | xfree(server_kexinit); | ||
1749 | BN_free(dh_client_pub); | ||
1750 | #ifdef DEBUG_KEXDH | ||
1751 | fprintf(stderr, "hash == "); | ||
1752 | for (i = 0; i< 20; i++) | ||
1753 | fprintf(stderr, "%02x", (hash[i])&0xff); | ||
1754 | fprintf(stderr, "\n"); | ||
1755 | #endif | ||
1756 | /* save session id := H */ | ||
1757 | /* XXX hashlen depends on KEX */ | ||
1758 | session_id2_len = 20; | ||
1759 | session_id2 = xmalloc(session_id2_len); | ||
1760 | memcpy(session_id2, hash, session_id2_len); | ||
1761 | |||
1762 | /* sign H */ | ||
1763 | /* XXX hashlen depends on KEX */ | ||
1764 | key_sign(hostkey, &signature, &slen, hash, 20); | ||
1765 | |||
1766 | destroy_sensitive_data(); | ||
1767 | |||
1768 | /* send server hostkey, DH pubkey 'f' and singed H */ | ||
1769 | packet_start(SSH2_MSG_KEX_DH_GEX_REPLY); | ||
1770 | packet_put_string((char *)server_host_key_blob, sbloblen); | ||
1771 | packet_put_bignum2(dh->pub_key); /* f */ | ||
1772 | packet_put_string((char *)signature, slen); | ||
1773 | packet_send(); | ||
1774 | xfree(signature); | ||
1775 | xfree(server_host_key_blob); | ||
1776 | packet_write_wait(); | ||
1777 | |||
1778 | kex_derive_keys(kex, hash, shared_secret); | ||
1779 | BN_clear_free(shared_secret); | ||
1780 | packet_set_kex(kex); | ||
1781 | |||
1782 | /* have keys, free DH */ | ||
1783 | DH_free(dh); | ||
1784 | } | 1445 | } |