summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Miller <djm@mindrot.org>2003-02-24 12:03:03 +1100
committerDamien Miller <djm@mindrot.org>2003-02-24 12:03:03 +1100
commit8e7fb335235bd6a7f8387a40bf71eaf9798f6f7e (patch)
tree46ba3e898aebfc99e531d793bccac6c0eba5e87d
parent1587fb8a174f57a064d603bbd595c3369aa697aa (diff)
- markus@cvs.openbsd.org 2003/02/16 17:09:57
[kex.c kexdh.c kexgex.c kex.h sshconnect2.c sshd.c ssh-keyscan.c] split kex into client and server code, no need to link server code into the client; ok provos@
-rw-r--r--ChangeLog6
-rw-r--r--kex.c23
-rw-r--r--kex.h23
-rw-r--r--kexdh.c234
-rw-r--r--kexdhc.c137
-rw-r--r--kexdhs.c138
-rw-r--r--kexgex.c328
-rw-r--r--kexgexc.c189
-rw-r--r--kexgexs.c186
-rw-r--r--ssh-keyscan.c4
-rw-r--r--sshconnect2.c4
-rw-r--r--sshd.c8
12 files changed, 697 insertions, 583 deletions
diff --git a/ChangeLog b/ChangeLog
index 586c10b5b..2fdcb2782 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -63,6 +63,10 @@
63 - markus@cvs.openbsd.org 2003/02/12 21:39:50 63 - markus@cvs.openbsd.org 2003/02/12 21:39:50
64 [crc32.c crc32.h] 64 [crc32.c crc32.h]
65 replace crc32.c with a BSD licensed version; noted by David Turner 65 replace crc32.c with a BSD licensed version; noted by David Turner
66 - markus@cvs.openbsd.org 2003/02/16 17:09:57
67 [kex.c kexdh.c kexgex.c kex.h sshconnect2.c sshd.c ssh-keyscan.c]
68 split kex into client and server code, no need to link
69 server code into the client; ok provos@
66 70
6720030211 7120030211
68 - (djm) Cygwin needs libcrypt too. Patch from vinschen@redhat.com 72 - (djm) Cygwin needs libcrypt too. Patch from vinschen@redhat.com
@@ -1163,4 +1167,4 @@
1163 save auth method before monitor_reset_key_state(); bugzilla bug #284; 1167 save auth method before monitor_reset_key_state(); bugzilla bug #284;
1164 ok provos@ 1168 ok provos@
1165 1169
1166$Id: ChangeLog,v 1.2611 2003/02/24 01:02:12 djm Exp $ 1170$Id: ChangeLog,v 1.2612 2003/02/24 01:03:03 djm Exp $
diff --git a/kex.c b/kex.c
index 0a861fb97..2c1cacfec 100644
--- a/kex.c
+++ b/kex.c
@@ -23,7 +23,7 @@
23 */ 23 */
24 24
25#include "includes.h" 25#include "includes.h"
26RCSID("$OpenBSD: kex.c,v 1.53 2003/02/02 10:56:08 markus Exp $"); 26RCSID("$OpenBSD: kex.c,v 1.54 2003/02/16 17:09:57 markus Exp $");
27 27
28#include <openssl/crypto.h> 28#include <openssl/crypto.h>
29 29
@@ -44,11 +44,6 @@ RCSID("$OpenBSD: kex.c,v 1.53 2003/02/02 10:56:08 markus Exp $");
44 44
45#define KEX_COOKIE_LEN 16 45#define KEX_COOKIE_LEN 16
46 46
47/* Use privilege separation for sshd */
48int use_privsep;
49struct monitor *pmonitor;
50
51
52/* prototype */ 47/* prototype */
53static void kex_kexinit_finish(Kex *); 48static void kex_kexinit_finish(Kex *);
54static void kex_choose_conf(Kex *); 49static void kex_choose_conf(Kex *);
@@ -237,14 +232,10 @@ kex_kexinit_finish(Kex *kex)
237 232
238 kex_choose_conf(kex); 233 kex_choose_conf(kex);
239 234
240 switch (kex->kex_type) { 235 if (kex->kex_type >= 0 && kex->kex_type < KEX_MAX &&
241 case DH_GRP1_SHA1: 236 kex->kex[kex->kex_type] != NULL) {
242 kexdh(kex); 237 (kex->kex[kex->kex_type])(kex);
243 break; 238 } else {
244 case DH_GEX_SHA1:
245 kexgex(kex);
246 break;
247 default:
248 fatal("Unsupported key exchange %d", kex->kex_type); 239 fatal("Unsupported key exchange %d", kex->kex_type);
249 } 240 }
250} 241}
@@ -301,9 +292,9 @@ choose_kex(Kex *k, char *client, char *server)
301 if (k->name == NULL) 292 if (k->name == NULL)
302 fatal("no kex alg"); 293 fatal("no kex alg");
303 if (strcmp(k->name, KEX_DH1) == 0) { 294 if (strcmp(k->name, KEX_DH1) == 0) {
304 k->kex_type = DH_GRP1_SHA1; 295 k->kex_type = KEX_DH_GRP1_SHA1;
305 } else if (strcmp(k->name, KEX_DHGEX) == 0) { 296 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
306 k->kex_type = DH_GEX_SHA1; 297 k->kex_type = KEX_DH_GEX_SHA1;
307 } else 298 } else
308 fatal("bad kex alg %s", k->name); 299 fatal("bad kex alg %s", k->name);
309} 300}
diff --git a/kex.h b/kex.h
index 93a529e12..52d442e9a 100644
--- a/kex.h
+++ b/kex.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: kex.h,v 1.32 2002/09/09 14:54:14 markus Exp $ */ 1/* $OpenBSD: kex.h,v 1.33 2003/02/16 17:09:57 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.
@@ -55,8 +55,9 @@ enum kex_modes {
55}; 55};
56 56
57enum kex_exchange { 57enum kex_exchange {
58 DH_GRP1_SHA1, 58 KEX_DH_GRP1_SHA1,
59 DH_GEX_SHA1 59 KEX_DH_GEX_SHA1,
60 KEX_MAX
60}; 61};
61 62
62#define KEX_INIT_SENT 0x0001 63#define KEX_INIT_SENT 0x0001
@@ -112,6 +113,7 @@ struct Kex {
112 int (*verify_host_key)(Key *); 113 int (*verify_host_key)(Key *);
113 Key *(*load_host_key)(int); 114 Key *(*load_host_key)(int);
114 int (*host_key_index)(Key *); 115 int (*host_key_index)(Key *);
116 void (*kex[KEX_MAX])(Kex *);
115}; 117};
116 118
117Kex *kex_setup(char *[PROPOSAL_MAX]); 119Kex *kex_setup(char *[PROPOSAL_MAX]);
@@ -121,11 +123,20 @@ void kex_send_kexinit(Kex *);
121void kex_input_kexinit(int, u_int32_t, void *); 123void kex_input_kexinit(int, u_int32_t, void *);
122void kex_derive_keys(Kex *, u_char *, BIGNUM *); 124void kex_derive_keys(Kex *, u_char *, BIGNUM *);
123 125
124void kexdh(Kex *);
125void kexgex(Kex *);
126
127Newkeys *kex_get_newkeys(int); 126Newkeys *kex_get_newkeys(int);
128 127
128void kexdh_client(Kex *);
129void kexdh_server(Kex *);
130void kexgex_client(Kex *);
131void kexgex_server(Kex *);
132
133u_char *
134kex_dh_hash(char *, char *, char *, int, char *, int, u_char *, int,
135 BIGNUM *, BIGNUM *, BIGNUM *);
136u_char *
137kexgex_hash(char *, char *, char *, int, char *, int, u_char *, int,
138 int, int, int, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *, BIGNUM *);
139
129#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH) 140#if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
130void dump_digest(char *, u_char *, int); 141void dump_digest(char *, u_char *, int);
131#endif 142#endif
diff --git a/kexdh.c b/kexdh.c
index 1e91e2550..4bbb7d1db 100644
--- a/kexdh.c
+++ b/kexdh.c
@@ -23,23 +23,16 @@
23 */ 23 */
24 24
25#include "includes.h" 25#include "includes.h"
26RCSID("$OpenBSD: kexdh.c,v 1.18 2002/03/18 17:50:31 provos Exp $"); 26RCSID("$OpenBSD: kexdh.c,v 1.19 2003/02/16 17:09:57 markus Exp $");
27 27
28#include <openssl/crypto.h> 28#include <openssl/evp.h>
29#include <openssl/bn.h>
30 29
31#include "xmalloc.h"
32#include "buffer.h" 30#include "buffer.h"
33#include "bufaux.h" 31#include "bufaux.h"
34#include "key.h"
35#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "ssh2.h" 32#include "ssh2.h"
40#include "monitor_wrap.h" 33#include "kex.h"
41 34
42static u_char * 35u_char *
43kex_dh_hash( 36kex_dh_hash(
44 char *client_version_string, 37 char *client_version_string,
45 char *server_version_string, 38 char *server_version_string,
@@ -86,222 +79,3 @@ kex_dh_hash(
86#endif 79#endif
87 return digest; 80 return digest;
88} 81}
89
90/* client */
91
92static void
93kexdh_client(Kex *kex)
94{
95 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
96 DH *dh;
97 Key *server_host_key;
98 u_char *server_host_key_blob = NULL, *signature = NULL;
99 u_char *kbuf, *hash;
100 u_int klen, kout, slen, sbloblen;
101
102 /* generate and send 'e', client DH public key */
103 dh = dh_new_group1();
104 dh_gen_key(dh, kex->we_need * 8);
105 packet_start(SSH2_MSG_KEXDH_INIT);
106 packet_put_bignum2(dh->pub_key);
107 packet_send();
108
109 debug("sending SSH2_MSG_KEXDH_INIT");
110#ifdef DEBUG_KEXDH
111 DHparams_print_fp(stderr, dh);
112 fprintf(stderr, "pub= ");
113 BN_print_fp(stderr, dh->pub_key);
114 fprintf(stderr, "\n");
115#endif
116
117 debug("expecting SSH2_MSG_KEXDH_REPLY");
118 packet_read_expect(SSH2_MSG_KEXDH_REPLY);
119
120 /* key, cert */
121 server_host_key_blob = packet_get_string(&sbloblen);
122 server_host_key = key_from_blob(server_host_key_blob, sbloblen);
123 if (server_host_key == NULL)
124 fatal("cannot decode server_host_key_blob");
125 if (server_host_key->type != kex->hostkey_type)
126 fatal("type mismatch for decoded server_host_key_blob");
127 if (kex->verify_host_key == NULL)
128 fatal("cannot verify server_host_key");
129 if (kex->verify_host_key(server_host_key) == -1)
130 fatal("server_host_key verification failed");
131
132 /* DH paramter f, server public DH key */
133 if ((dh_server_pub = BN_new()) == NULL)
134 fatal("dh_server_pub == NULL");
135 packet_get_bignum2(dh_server_pub);
136
137#ifdef DEBUG_KEXDH
138 fprintf(stderr, "dh_server_pub= ");
139 BN_print_fp(stderr, dh_server_pub);
140 fprintf(stderr, "\n");
141 debug("bits %d", BN_num_bits(dh_server_pub));
142#endif
143
144 /* signed H */
145 signature = packet_get_string(&slen);
146 packet_check_eom();
147
148 if (!dh_pub_is_valid(dh, dh_server_pub))
149 packet_disconnect("bad server public DH value");
150
151 klen = DH_size(dh);
152 kbuf = xmalloc(klen);
153 kout = DH_compute_key(kbuf, dh_server_pub, dh);
154#ifdef DEBUG_KEXDH
155 dump_digest("shared secret", kbuf, kout);
156#endif
157 if ((shared_secret = BN_new()) == NULL)
158 fatal("kexdh_client: BN_new failed");
159 BN_bin2bn(kbuf, kout, shared_secret);
160 memset(kbuf, 0, klen);
161 xfree(kbuf);
162
163 /* calc and verify H */
164 hash = kex_dh_hash(
165 kex->client_version_string,
166 kex->server_version_string,
167 buffer_ptr(&kex->my), buffer_len(&kex->my),
168 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
169 server_host_key_blob, sbloblen,
170 dh->pub_key,
171 dh_server_pub,
172 shared_secret
173 );
174 xfree(server_host_key_blob);
175 BN_clear_free(dh_server_pub);
176 DH_free(dh);
177
178 if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
179 fatal("key_verify failed for server_host_key");
180 key_free(server_host_key);
181 xfree(signature);
182
183 /* save session id */
184 if (kex->session_id == NULL) {
185 kex->session_id_len = 20;
186 kex->session_id = xmalloc(kex->session_id_len);
187 memcpy(kex->session_id, hash, kex->session_id_len);
188 }
189
190 kex_derive_keys(kex, hash, shared_secret);
191 BN_clear_free(shared_secret);
192 kex_finish(kex);
193}
194
195/* server */
196
197static void
198kexdh_server(Kex *kex)
199{
200 BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
201 DH *dh;
202 Key *server_host_key;
203 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
204 u_int sbloblen, klen, kout;
205 u_int slen;
206
207 /* generate server DH public key */
208 dh = dh_new_group1();
209 dh_gen_key(dh, kex->we_need * 8);
210
211 debug("expecting SSH2_MSG_KEXDH_INIT");
212 packet_read_expect(SSH2_MSG_KEXDH_INIT);
213
214 if (kex->load_host_key == NULL)
215 fatal("Cannot load hostkey");
216 server_host_key = kex->load_host_key(kex->hostkey_type);
217 if (server_host_key == NULL)
218 fatal("Unsupported hostkey type %d", kex->hostkey_type);
219
220 /* key, cert */
221 if ((dh_client_pub = BN_new()) == NULL)
222 fatal("dh_client_pub == NULL");
223 packet_get_bignum2(dh_client_pub);
224 packet_check_eom();
225
226#ifdef DEBUG_KEXDH
227 fprintf(stderr, "dh_client_pub= ");
228 BN_print_fp(stderr, dh_client_pub);
229 fprintf(stderr, "\n");
230 debug("bits %d", BN_num_bits(dh_client_pub));
231#endif
232
233#ifdef DEBUG_KEXDH
234 DHparams_print_fp(stderr, dh);
235 fprintf(stderr, "pub= ");
236 BN_print_fp(stderr, dh->pub_key);
237 fprintf(stderr, "\n");
238#endif
239 if (!dh_pub_is_valid(dh, dh_client_pub))
240 packet_disconnect("bad client public DH value");
241
242 klen = DH_size(dh);
243 kbuf = xmalloc(klen);
244 kout = DH_compute_key(kbuf, dh_client_pub, dh);
245#ifdef DEBUG_KEXDH
246 dump_digest("shared secret", kbuf, kout);
247#endif
248 if ((shared_secret = BN_new()) == NULL)
249 fatal("kexdh_server: BN_new failed");
250 BN_bin2bn(kbuf, kout, shared_secret);
251 memset(kbuf, 0, klen);
252 xfree(kbuf);
253
254 key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
255
256 /* calc H */
257 hash = kex_dh_hash(
258 kex->client_version_string,
259 kex->server_version_string,
260 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
261 buffer_ptr(&kex->my), buffer_len(&kex->my),
262 server_host_key_blob, sbloblen,
263 dh_client_pub,
264 dh->pub_key,
265 shared_secret
266 );
267 BN_clear_free(dh_client_pub);
268
269 /* save session id := H */
270 /* XXX hashlen depends on KEX */
271 if (kex->session_id == NULL) {
272 kex->session_id_len = 20;
273 kex->session_id = xmalloc(kex->session_id_len);
274 memcpy(kex->session_id, hash, kex->session_id_len);
275 }
276
277 /* sign H */
278 /* XXX hashlen depends on KEX */
279 PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20));
280
281 /* destroy_sensitive_data(); */
282
283 /* send server hostkey, DH pubkey 'f' and singed H */
284 packet_start(SSH2_MSG_KEXDH_REPLY);
285 packet_put_string(server_host_key_blob, sbloblen);
286 packet_put_bignum2(dh->pub_key); /* f */
287 packet_put_string(signature, slen);
288 packet_send();
289
290 xfree(signature);
291 xfree(server_host_key_blob);
292 /* have keys, free DH */
293 DH_free(dh);
294
295 kex_derive_keys(kex, hash, shared_secret);
296 BN_clear_free(shared_secret);
297 kex_finish(kex);
298}
299
300void
301kexdh(Kex *kex)
302{
303 if (kex->server)
304 kexdh_server(kex);
305 else
306 kexdh_client(kex);
307}
diff --git a/kexdhc.c b/kexdhc.c
new file mode 100644
index 000000000..fe6dc53f8
--- /dev/null
+++ b/kexdhc.c
@@ -0,0 +1,137 @@
1/*
2 * Copyright (c) 2001 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26RCSID("$OpenBSD: kexdhc.c,v 1.1 2003/02/16 17:09:57 markus Exp $");
27
28#include "xmalloc.h"
29#include "key.h"
30#include "kex.h"
31#include "log.h"
32#include "packet.h"
33#include "dh.h"
34#include "ssh2.h"
35
36void
37kexdh_client(Kex *kex)
38{
39 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
40 DH *dh;
41 Key *server_host_key;
42 u_char *server_host_key_blob = NULL, *signature = NULL;
43 u_char *kbuf, *hash;
44 u_int klen, kout, slen, sbloblen;
45
46 /* generate and send 'e', client DH public key */
47 dh = dh_new_group1();
48 dh_gen_key(dh, kex->we_need * 8);
49 packet_start(SSH2_MSG_KEXDH_INIT);
50 packet_put_bignum2(dh->pub_key);
51 packet_send();
52
53 debug("sending SSH2_MSG_KEXDH_INIT");
54#ifdef DEBUG_KEXDH
55 DHparams_print_fp(stderr, dh);
56 fprintf(stderr, "pub= ");
57 BN_print_fp(stderr, dh->pub_key);
58 fprintf(stderr, "\n");
59#endif
60
61 debug("expecting SSH2_MSG_KEXDH_REPLY");
62 packet_read_expect(SSH2_MSG_KEXDH_REPLY);
63
64 /* key, cert */
65 server_host_key_blob = packet_get_string(&sbloblen);
66 server_host_key = key_from_blob(server_host_key_blob, sbloblen);
67 if (server_host_key == NULL)
68 fatal("cannot decode server_host_key_blob");
69 if (server_host_key->type != kex->hostkey_type)
70 fatal("type mismatch for decoded server_host_key_blob");
71 if (kex->verify_host_key == NULL)
72 fatal("cannot verify server_host_key");
73 if (kex->verify_host_key(server_host_key) == -1)
74 fatal("server_host_key verification failed");
75
76 /* DH paramter f, server public DH key */
77 if ((dh_server_pub = BN_new()) == NULL)
78 fatal("dh_server_pub == NULL");
79 packet_get_bignum2(dh_server_pub);
80
81#ifdef DEBUG_KEXDH
82 fprintf(stderr, "dh_server_pub= ");
83 BN_print_fp(stderr, dh_server_pub);
84 fprintf(stderr, "\n");
85 debug("bits %d", BN_num_bits(dh_server_pub));
86#endif
87
88 /* signed H */
89 signature = packet_get_string(&slen);
90 packet_check_eom();
91
92 if (!dh_pub_is_valid(dh, dh_server_pub))
93 packet_disconnect("bad server public DH value");
94
95 klen = DH_size(dh);
96 kbuf = xmalloc(klen);
97 kout = DH_compute_key(kbuf, dh_server_pub, dh);
98#ifdef DEBUG_KEXDH
99 dump_digest("shared secret", kbuf, kout);
100#endif
101 if ((shared_secret = BN_new()) == NULL)
102 fatal("kexdh_client: BN_new failed");
103 BN_bin2bn(kbuf, kout, shared_secret);
104 memset(kbuf, 0, klen);
105 xfree(kbuf);
106
107 /* calc and verify H */
108 hash = kex_dh_hash(
109 kex->client_version_string,
110 kex->server_version_string,
111 buffer_ptr(&kex->my), buffer_len(&kex->my),
112 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
113 server_host_key_blob, sbloblen,
114 dh->pub_key,
115 dh_server_pub,
116 shared_secret
117 );
118 xfree(server_host_key_blob);
119 BN_clear_free(dh_server_pub);
120 DH_free(dh);
121
122 if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
123 fatal("key_verify failed for server_host_key");
124 key_free(server_host_key);
125 xfree(signature);
126
127 /* save session id */
128 if (kex->session_id == NULL) {
129 kex->session_id_len = 20;
130 kex->session_id = xmalloc(kex->session_id_len);
131 memcpy(kex->session_id, hash, kex->session_id_len);
132 }
133
134 kex_derive_keys(kex, hash, shared_secret);
135 BN_clear_free(shared_secret);
136 kex_finish(kex);
137}
diff --git a/kexdhs.c b/kexdhs.c
new file mode 100644
index 000000000..f04bce825
--- /dev/null
+++ b/kexdhs.c
@@ -0,0 +1,138 @@
1/*
2 * Copyright (c) 2001 Markus Friedl. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26RCSID("$OpenBSD: kexdhs.c,v 1.1 2003/02/16 17:09:57 markus Exp $");
27
28#include "xmalloc.h"
29#include "key.h"
30#include "kex.h"
31#include "log.h"
32#include "packet.h"
33#include "dh.h"
34#include "ssh2.h"
35#include "monitor_wrap.h"
36
37void
38kexdh_server(Kex *kex)
39{
40 BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
41 DH *dh;
42 Key *server_host_key;
43 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
44 u_int sbloblen, klen, kout;
45 u_int slen;
46
47 /* generate server DH public key */
48 dh = dh_new_group1();
49 dh_gen_key(dh, kex->we_need * 8);
50
51 debug("expecting SSH2_MSG_KEXDH_INIT");
52 packet_read_expect(SSH2_MSG_KEXDH_INIT);
53
54 if (kex->load_host_key == NULL)
55 fatal("Cannot load hostkey");
56 server_host_key = kex->load_host_key(kex->hostkey_type);
57 if (server_host_key == NULL)
58 fatal("Unsupported hostkey type %d", kex->hostkey_type);
59
60 /* key, cert */
61 if ((dh_client_pub = BN_new()) == NULL)
62 fatal("dh_client_pub == NULL");
63 packet_get_bignum2(dh_client_pub);
64 packet_check_eom();
65
66#ifdef DEBUG_KEXDH
67 fprintf(stderr, "dh_client_pub= ");
68 BN_print_fp(stderr, dh_client_pub);
69 fprintf(stderr, "\n");
70 debug("bits %d", BN_num_bits(dh_client_pub));
71#endif
72
73#ifdef DEBUG_KEXDH
74 DHparams_print_fp(stderr, dh);
75 fprintf(stderr, "pub= ");
76 BN_print_fp(stderr, dh->pub_key);
77 fprintf(stderr, "\n");
78#endif
79 if (!dh_pub_is_valid(dh, dh_client_pub))
80 packet_disconnect("bad client public DH value");
81
82 klen = DH_size(dh);
83 kbuf = xmalloc(klen);
84 kout = DH_compute_key(kbuf, dh_client_pub, dh);
85#ifdef DEBUG_KEXDH
86 dump_digest("shared secret", kbuf, kout);
87#endif
88 if ((shared_secret = BN_new()) == NULL)
89 fatal("kexdh_server: BN_new failed");
90 BN_bin2bn(kbuf, kout, shared_secret);
91 memset(kbuf, 0, klen);
92 xfree(kbuf);
93
94 key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
95
96 /* calc H */
97 hash = kex_dh_hash(
98 kex->client_version_string,
99 kex->server_version_string,
100 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
101 buffer_ptr(&kex->my), buffer_len(&kex->my),
102 server_host_key_blob, sbloblen,
103 dh_client_pub,
104 dh->pub_key,
105 shared_secret
106 );
107 BN_clear_free(dh_client_pub);
108
109 /* save session id := H */
110 /* XXX hashlen depends on KEX */
111 if (kex->session_id == NULL) {
112 kex->session_id_len = 20;
113 kex->session_id = xmalloc(kex->session_id_len);
114 memcpy(kex->session_id, hash, kex->session_id_len);
115 }
116
117 /* sign H */
118 /* XXX hashlen depends on KEX */
119 PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20));
120
121 /* destroy_sensitive_data(); */
122
123 /* send server hostkey, DH pubkey 'f' and singed H */
124 packet_start(SSH2_MSG_KEXDH_REPLY);
125 packet_put_string(server_host_key_blob, sbloblen);
126 packet_put_bignum2(dh->pub_key); /* f */
127 packet_put_string(signature, slen);
128 packet_send();
129
130 xfree(signature);
131 xfree(server_host_key_blob);
132 /* have keys, free DH */
133 DH_free(dh);
134
135 kex_derive_keys(kex, hash, shared_secret);
136 BN_clear_free(shared_secret);
137 kex_finish(kex);
138}
diff --git a/kexgex.c b/kexgex.c
index 2d4a58153..b0c39c8cb 100644
--- a/kexgex.c
+++ b/kexgex.c
@@ -24,23 +24,16 @@
24 */ 24 */
25 25
26#include "includes.h" 26#include "includes.h"
27RCSID("$OpenBSD: kexgex.c,v 1.22 2002/03/24 17:27:03 stevesk Exp $"); 27RCSID("$OpenBSD: kexgex.c,v 1.23 2003/02/16 17:09:57 markus Exp $");
28 28
29#include <openssl/bn.h> 29#include <openssl/evp.h>
30 30
31#include "xmalloc.h"
32#include "buffer.h" 31#include "buffer.h"
33#include "bufaux.h" 32#include "bufaux.h"
34#include "key.h"
35#include "kex.h" 33#include "kex.h"
36#include "log.h"
37#include "packet.h"
38#include "dh.h"
39#include "ssh2.h" 34#include "ssh2.h"
40#include "compat.h"
41#include "monitor_wrap.h"
42 35
43static u_char * 36u_char *
44kexgex_hash( 37kexgex_hash(
45 char *client_version_string, 38 char *client_version_string,
46 char *server_version_string, 39 char *server_version_string,
@@ -97,318 +90,3 @@ kexgex_hash(
97#endif 90#endif
98 return digest; 91 return digest;
99} 92}
100
101/* client */
102
103static void
104kexgex_client(Kex *kex)
105{
106 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
107 BIGNUM *p = NULL, *g = NULL;
108 Key *server_host_key;
109 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
110 u_int klen, kout, slen, sbloblen;
111 int min, max, nbits;
112 DH *dh;
113
114 nbits = dh_estimate(kex->we_need * 8);
115
116 if (datafellows & SSH_OLD_DHGEX) {
117 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
118
119 /* Old GEX request */
120 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
121 packet_put_int(nbits);
122 min = DH_GRP_MIN;
123 max = DH_GRP_MAX;
124 } else {
125 debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
126
127 /* New GEX request */
128 min = DH_GRP_MIN;
129 max = DH_GRP_MAX;
130 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
131 packet_put_int(min);
132 packet_put_int(nbits);
133 packet_put_int(max);
134 }
135#ifdef DEBUG_KEXDH
136 fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
137 min, nbits, max);
138#endif
139 packet_send();
140
141 debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
142 packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP);
143
144 if ((p = BN_new()) == NULL)
145 fatal("BN_new");
146 packet_get_bignum2(p);
147 if ((g = BN_new()) == NULL)
148 fatal("BN_new");
149 packet_get_bignum2(g);
150 packet_check_eom();
151
152 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
153 fatal("DH_GEX group out of range: %d !< %d !< %d",
154 min, BN_num_bits(p), max);
155
156 dh = dh_new_group(g, p);
157 dh_gen_key(dh, kex->we_need * 8);
158
159#ifdef DEBUG_KEXDH
160 DHparams_print_fp(stderr, dh);
161 fprintf(stderr, "pub= ");
162 BN_print_fp(stderr, dh->pub_key);
163 fprintf(stderr, "\n");
164#endif
165
166 debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
167 /* generate and send 'e', client DH public key */
168 packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
169 packet_put_bignum2(dh->pub_key);
170 packet_send();
171
172 debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
173 packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY);
174
175 /* key, cert */
176 server_host_key_blob = packet_get_string(&sbloblen);
177 server_host_key = key_from_blob(server_host_key_blob, sbloblen);
178 if (server_host_key == NULL)
179 fatal("cannot decode server_host_key_blob");
180 if (server_host_key->type != kex->hostkey_type)
181 fatal("type mismatch for decoded server_host_key_blob");
182 if (kex->verify_host_key == NULL)
183 fatal("cannot verify server_host_key");
184 if (kex->verify_host_key(server_host_key) == -1)
185 fatal("server_host_key verification failed");
186
187 /* DH paramter f, server public DH key */
188 if ((dh_server_pub = BN_new()) == NULL)
189 fatal("dh_server_pub == NULL");
190 packet_get_bignum2(dh_server_pub);
191
192#ifdef DEBUG_KEXDH
193 fprintf(stderr, "dh_server_pub= ");
194 BN_print_fp(stderr, dh_server_pub);
195 fprintf(stderr, "\n");
196 debug("bits %d", BN_num_bits(dh_server_pub));
197#endif
198
199 /* signed H */
200 signature = packet_get_string(&slen);
201 packet_check_eom();
202
203 if (!dh_pub_is_valid(dh, dh_server_pub))
204 packet_disconnect("bad server public DH value");
205
206 klen = DH_size(dh);
207 kbuf = xmalloc(klen);
208 kout = DH_compute_key(kbuf, dh_server_pub, dh);
209#ifdef DEBUG_KEXDH
210 dump_digest("shared secret", kbuf, kout);
211#endif
212 if ((shared_secret = BN_new()) == NULL)
213 fatal("kexgex_client: BN_new failed");
214 BN_bin2bn(kbuf, kout, shared_secret);
215 memset(kbuf, 0, klen);
216 xfree(kbuf);
217
218 if (datafellows & SSH_OLD_DHGEX)
219 min = max = -1;
220
221 /* calc and verify H */
222 hash = kexgex_hash(
223 kex->client_version_string,
224 kex->server_version_string,
225 buffer_ptr(&kex->my), buffer_len(&kex->my),
226 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
227 server_host_key_blob, sbloblen,
228 min, nbits, max,
229 dh->p, dh->g,
230 dh->pub_key,
231 dh_server_pub,
232 shared_secret
233 );
234 /* have keys, free DH */
235 DH_free(dh);
236 xfree(server_host_key_blob);
237 BN_clear_free(dh_server_pub);
238
239 if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
240 fatal("key_verify failed for server_host_key");
241 key_free(server_host_key);
242 xfree(signature);
243
244 /* save session id */
245 if (kex->session_id == NULL) {
246 kex->session_id_len = 20;
247 kex->session_id = xmalloc(kex->session_id_len);
248 memcpy(kex->session_id, hash, kex->session_id_len);
249 }
250 kex_derive_keys(kex, hash, shared_secret);
251 BN_clear_free(shared_secret);
252
253 kex_finish(kex);
254}
255
256/* server */
257
258static void
259kexgex_server(Kex *kex)
260{
261 BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
262 Key *server_host_key;
263 DH *dh;
264 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
265 u_int sbloblen, klen, kout, slen;
266 int min = -1, max = -1, nbits = -1, type;
267
268 if (kex->load_host_key == NULL)
269 fatal("Cannot load hostkey");
270 server_host_key = kex->load_host_key(kex->hostkey_type);
271 if (server_host_key == NULL)
272 fatal("Unsupported hostkey type %d", kex->hostkey_type);
273
274 type = packet_read();
275 switch (type) {
276 case SSH2_MSG_KEX_DH_GEX_REQUEST:
277 debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
278 min = packet_get_int();
279 nbits = packet_get_int();
280 max = packet_get_int();
281 min = MAX(DH_GRP_MIN, min);
282 max = MIN(DH_GRP_MAX, max);
283 break;
284 case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
285 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
286 nbits = packet_get_int();
287 min = DH_GRP_MIN;
288 max = DH_GRP_MAX;
289 /* unused for old GEX */
290 break;
291 default:
292 fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
293 }
294 packet_check_eom();
295
296 if (max < min || nbits < min || max < nbits)
297 fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
298 min, nbits, max);
299
300 /* Contact privileged parent */
301 dh = PRIVSEP(choose_dh(min, nbits, max));
302 if (dh == NULL)
303 packet_disconnect("Protocol error: no matching DH grp found");
304
305 debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
306 packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
307 packet_put_bignum2(dh->p);
308 packet_put_bignum2(dh->g);
309 packet_send();
310
311 /* flush */
312 packet_write_wait();
313
314 /* Compute our exchange value in parallel with the client */
315 dh_gen_key(dh, kex->we_need * 8);
316
317 debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
318 packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT);
319
320 /* key, cert */
321 if ((dh_client_pub = BN_new()) == NULL)
322 fatal("dh_client_pub == NULL");
323 packet_get_bignum2(dh_client_pub);
324 packet_check_eom();
325
326#ifdef DEBUG_KEXDH
327 fprintf(stderr, "dh_client_pub= ");
328 BN_print_fp(stderr, dh_client_pub);
329 fprintf(stderr, "\n");
330 debug("bits %d", BN_num_bits(dh_client_pub));
331#endif
332
333#ifdef DEBUG_KEXDH
334 DHparams_print_fp(stderr, dh);
335 fprintf(stderr, "pub= ");
336 BN_print_fp(stderr, dh->pub_key);
337 fprintf(stderr, "\n");
338#endif
339 if (!dh_pub_is_valid(dh, dh_client_pub))
340 packet_disconnect("bad client public DH value");
341
342 klen = DH_size(dh);
343 kbuf = xmalloc(klen);
344 kout = DH_compute_key(kbuf, dh_client_pub, dh);
345#ifdef DEBUG_KEXDH
346 dump_digest("shared secret", kbuf, kout);
347#endif
348 if ((shared_secret = BN_new()) == NULL)
349 fatal("kexgex_server: BN_new failed");
350 BN_bin2bn(kbuf, kout, shared_secret);
351 memset(kbuf, 0, klen);
352 xfree(kbuf);
353
354 key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
355
356 if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
357 min = max = -1;
358
359 /* calc H */ /* XXX depends on 'kex' */
360 hash = kexgex_hash(
361 kex->client_version_string,
362 kex->server_version_string,
363 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
364 buffer_ptr(&kex->my), buffer_len(&kex->my),
365 server_host_key_blob, sbloblen,
366 min, nbits, max,
367 dh->p, dh->g,
368 dh_client_pub,
369 dh->pub_key,
370 shared_secret
371 );
372 BN_clear_free(dh_client_pub);
373
374 /* save session id := H */
375 /* XXX hashlen depends on KEX */
376 if (kex->session_id == NULL) {
377 kex->session_id_len = 20;
378 kex->session_id = xmalloc(kex->session_id_len);
379 memcpy(kex->session_id, hash, kex->session_id_len);
380 }
381
382 /* sign H */
383 /* XXX hashlen depends on KEX */
384 PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20));
385
386 /* destroy_sensitive_data(); */
387
388 /* send server hostkey, DH pubkey 'f' and singed H */
389 debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
390 packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
391 packet_put_string(server_host_key_blob, sbloblen);
392 packet_put_bignum2(dh->pub_key); /* f */
393 packet_put_string(signature, slen);
394 packet_send();
395
396 xfree(signature);
397 xfree(server_host_key_blob);
398 /* have keys, free DH */
399 DH_free(dh);
400
401 kex_derive_keys(kex, hash, shared_secret);
402 BN_clear_free(shared_secret);
403
404 kex_finish(kex);
405}
406
407void
408kexgex(Kex *kex)
409{
410 if (kex->server)
411 kexgex_server(kex);
412 else
413 kexgex_client(kex);
414}
diff --git a/kexgexc.c b/kexgexc.c
new file mode 100644
index 000000000..f14ac44ca
--- /dev/null
+++ b/kexgexc.c
@@ -0,0 +1,189 @@
1/*
2 * Copyright (c) 2000 Niels Provos. All rights reserved.
3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27RCSID("$OpenBSD: kexgexc.c,v 1.1 2003/02/16 17:09:57 markus Exp $");
28
29#include "xmalloc.h"
30#include "key.h"
31#include "kex.h"
32#include "log.h"
33#include "packet.h"
34#include "dh.h"
35#include "ssh2.h"
36#include "compat.h"
37
38void
39kexgex_client(Kex *kex)
40{
41 BIGNUM *dh_server_pub = NULL, *shared_secret = NULL;
42 BIGNUM *p = NULL, *g = NULL;
43 Key *server_host_key;
44 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
45 u_int klen, kout, slen, sbloblen;
46 int min, max, nbits;
47 DH *dh;
48
49 nbits = dh_estimate(kex->we_need * 8);
50
51 if (datafellows & SSH_OLD_DHGEX) {
52 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD sent");
53
54 /* Old GEX request */
55 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST_OLD);
56 packet_put_int(nbits);
57 min = DH_GRP_MIN;
58 max = DH_GRP_MAX;
59 } else {
60 debug("SSH2_MSG_KEX_DH_GEX_REQUEST sent");
61
62 /* New GEX request */
63 min = DH_GRP_MIN;
64 max = DH_GRP_MAX;
65 packet_start(SSH2_MSG_KEX_DH_GEX_REQUEST);
66 packet_put_int(min);
67 packet_put_int(nbits);
68 packet_put_int(max);
69 }
70#ifdef DEBUG_KEXDH
71 fprintf(stderr, "\nmin = %d, nbits = %d, max = %d\n",
72 min, nbits, max);
73#endif
74 packet_send();
75
76 debug("expecting SSH2_MSG_KEX_DH_GEX_GROUP");
77 packet_read_expect(SSH2_MSG_KEX_DH_GEX_GROUP);
78
79 if ((p = BN_new()) == NULL)
80 fatal("BN_new");
81 packet_get_bignum2(p);
82 if ((g = BN_new()) == NULL)
83 fatal("BN_new");
84 packet_get_bignum2(g);
85 packet_check_eom();
86
87 if (BN_num_bits(p) < min || BN_num_bits(p) > max)
88 fatal("DH_GEX group out of range: %d !< %d !< %d",
89 min, BN_num_bits(p), max);
90
91 dh = dh_new_group(g, p);
92 dh_gen_key(dh, kex->we_need * 8);
93
94#ifdef DEBUG_KEXDH
95 DHparams_print_fp(stderr, dh);
96 fprintf(stderr, "pub= ");
97 BN_print_fp(stderr, dh->pub_key);
98 fprintf(stderr, "\n");
99#endif
100
101 debug("SSH2_MSG_KEX_DH_GEX_INIT sent");
102 /* generate and send 'e', client DH public key */
103 packet_start(SSH2_MSG_KEX_DH_GEX_INIT);
104 packet_put_bignum2(dh->pub_key);
105 packet_send();
106
107 debug("expecting SSH2_MSG_KEX_DH_GEX_REPLY");
108 packet_read_expect(SSH2_MSG_KEX_DH_GEX_REPLY);
109
110 /* key, cert */
111 server_host_key_blob = packet_get_string(&sbloblen);
112 server_host_key = key_from_blob(server_host_key_blob, sbloblen);
113 if (server_host_key == NULL)
114 fatal("cannot decode server_host_key_blob");
115 if (server_host_key->type != kex->hostkey_type)
116 fatal("type mismatch for decoded server_host_key_blob");
117 if (kex->verify_host_key == NULL)
118 fatal("cannot verify server_host_key");
119 if (kex->verify_host_key(server_host_key) == -1)
120 fatal("server_host_key verification failed");
121
122 /* DH paramter f, server public DH key */
123 if ((dh_server_pub = BN_new()) == NULL)
124 fatal("dh_server_pub == NULL");
125 packet_get_bignum2(dh_server_pub);
126
127#ifdef DEBUG_KEXDH
128 fprintf(stderr, "dh_server_pub= ");
129 BN_print_fp(stderr, dh_server_pub);
130 fprintf(stderr, "\n");
131 debug("bits %d", BN_num_bits(dh_server_pub));
132#endif
133
134 /* signed H */
135 signature = packet_get_string(&slen);
136 packet_check_eom();
137
138 if (!dh_pub_is_valid(dh, dh_server_pub))
139 packet_disconnect("bad server public DH value");
140
141 klen = DH_size(dh);
142 kbuf = xmalloc(klen);
143 kout = DH_compute_key(kbuf, dh_server_pub, dh);
144#ifdef DEBUG_KEXDH
145 dump_digest("shared secret", kbuf, kout);
146#endif
147 if ((shared_secret = BN_new()) == NULL)
148 fatal("kexgex_client: BN_new failed");
149 BN_bin2bn(kbuf, kout, shared_secret);
150 memset(kbuf, 0, klen);
151 xfree(kbuf);
152
153 if (datafellows & SSH_OLD_DHGEX)
154 min = max = -1;
155
156 /* calc and verify H */
157 hash = kexgex_hash(
158 kex->client_version_string,
159 kex->server_version_string,
160 buffer_ptr(&kex->my), buffer_len(&kex->my),
161 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
162 server_host_key_blob, sbloblen,
163 min, nbits, max,
164 dh->p, dh->g,
165 dh->pub_key,
166 dh_server_pub,
167 shared_secret
168 );
169 /* have keys, free DH */
170 DH_free(dh);
171 xfree(server_host_key_blob);
172 BN_clear_free(dh_server_pub);
173
174 if (key_verify(server_host_key, signature, slen, hash, 20) != 1)
175 fatal("key_verify failed for server_host_key");
176 key_free(server_host_key);
177 xfree(signature);
178
179 /* save session id */
180 if (kex->session_id == NULL) {
181 kex->session_id_len = 20;
182 kex->session_id = xmalloc(kex->session_id_len);
183 memcpy(kex->session_id, hash, kex->session_id_len);
184 }
185 kex_derive_keys(kex, hash, shared_secret);
186 BN_clear_free(shared_secret);
187
188 kex_finish(kex);
189}
diff --git a/kexgexs.c b/kexgexs.c
new file mode 100644
index 000000000..baebfcfb0
--- /dev/null
+++ b/kexgexs.c
@@ -0,0 +1,186 @@
1/*
2 * Copyright (c) 2000 Niels Provos. All rights reserved.
3 * Copyright (c) 2001 Markus Friedl. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "includes.h"
27RCSID("$OpenBSD: kexgexs.c,v 1.1 2003/02/16 17:09:57 markus Exp $");
28
29#include "xmalloc.h"
30#include "key.h"
31#include "kex.h"
32#include "log.h"
33#include "packet.h"
34#include "dh.h"
35#include "ssh2.h"
36#include "compat.h"
37#include "monitor_wrap.h"
38
39void
40kexgex_server(Kex *kex)
41{
42 BIGNUM *shared_secret = NULL, *dh_client_pub = NULL;
43 Key *server_host_key;
44 DH *dh;
45 u_char *kbuf, *hash, *signature = NULL, *server_host_key_blob = NULL;
46 u_int sbloblen, klen, kout, slen;
47 int min = -1, max = -1, nbits = -1, type;
48
49 if (kex->load_host_key == NULL)
50 fatal("Cannot load hostkey");
51 server_host_key = kex->load_host_key(kex->hostkey_type);
52 if (server_host_key == NULL)
53 fatal("Unsupported hostkey type %d", kex->hostkey_type);
54
55 type = packet_read();
56 switch (type) {
57 case SSH2_MSG_KEX_DH_GEX_REQUEST:
58 debug("SSH2_MSG_KEX_DH_GEX_REQUEST received");
59 min = packet_get_int();
60 nbits = packet_get_int();
61 max = packet_get_int();
62 min = MAX(DH_GRP_MIN, min);
63 max = MIN(DH_GRP_MAX, max);
64 break;
65 case SSH2_MSG_KEX_DH_GEX_REQUEST_OLD:
66 debug("SSH2_MSG_KEX_DH_GEX_REQUEST_OLD received");
67 nbits = packet_get_int();
68 min = DH_GRP_MIN;
69 max = DH_GRP_MAX;
70 /* unused for old GEX */
71 break;
72 default:
73 fatal("protocol error during kex, no DH_GEX_REQUEST: %d", type);
74 }
75 packet_check_eom();
76
77 if (max < min || nbits < min || max < nbits)
78 fatal("DH_GEX_REQUEST, bad parameters: %d !< %d !< %d",
79 min, nbits, max);
80
81 /* Contact privileged parent */
82 dh = PRIVSEP(choose_dh(min, nbits, max));
83 if (dh == NULL)
84 packet_disconnect("Protocol error: no matching DH grp found");
85
86 debug("SSH2_MSG_KEX_DH_GEX_GROUP sent");
87 packet_start(SSH2_MSG_KEX_DH_GEX_GROUP);
88 packet_put_bignum2(dh->p);
89 packet_put_bignum2(dh->g);
90 packet_send();
91
92 /* flush */
93 packet_write_wait();
94
95 /* Compute our exchange value in parallel with the client */
96 dh_gen_key(dh, kex->we_need * 8);
97
98 debug("expecting SSH2_MSG_KEX_DH_GEX_INIT");
99 packet_read_expect(SSH2_MSG_KEX_DH_GEX_INIT);
100
101 /* key, cert */
102 if ((dh_client_pub = BN_new()) == NULL)
103 fatal("dh_client_pub == NULL");
104 packet_get_bignum2(dh_client_pub);
105 packet_check_eom();
106
107#ifdef DEBUG_KEXDH
108 fprintf(stderr, "dh_client_pub= ");
109 BN_print_fp(stderr, dh_client_pub);
110 fprintf(stderr, "\n");
111 debug("bits %d", BN_num_bits(dh_client_pub));
112#endif
113
114#ifdef DEBUG_KEXDH
115 DHparams_print_fp(stderr, dh);
116 fprintf(stderr, "pub= ");
117 BN_print_fp(stderr, dh->pub_key);
118 fprintf(stderr, "\n");
119#endif
120 if (!dh_pub_is_valid(dh, dh_client_pub))
121 packet_disconnect("bad client public DH value");
122
123 klen = DH_size(dh);
124 kbuf = xmalloc(klen);
125 kout = DH_compute_key(kbuf, dh_client_pub, dh);
126#ifdef DEBUG_KEXDH
127 dump_digest("shared secret", kbuf, kout);
128#endif
129 if ((shared_secret = BN_new()) == NULL)
130 fatal("kexgex_server: BN_new failed");
131 BN_bin2bn(kbuf, kout, shared_secret);
132 memset(kbuf, 0, klen);
133 xfree(kbuf);
134
135 key_to_blob(server_host_key, &server_host_key_blob, &sbloblen);
136
137 if (type == SSH2_MSG_KEX_DH_GEX_REQUEST_OLD)
138 min = max = -1;
139
140 /* calc H */ /* XXX depends on 'kex' */
141 hash = kexgex_hash(
142 kex->client_version_string,
143 kex->server_version_string,
144 buffer_ptr(&kex->peer), buffer_len(&kex->peer),
145 buffer_ptr(&kex->my), buffer_len(&kex->my),
146 server_host_key_blob, sbloblen,
147 min, nbits, max,
148 dh->p, dh->g,
149 dh_client_pub,
150 dh->pub_key,
151 shared_secret
152 );
153 BN_clear_free(dh_client_pub);
154
155 /* save session id := H */
156 /* XXX hashlen depends on KEX */
157 if (kex->session_id == NULL) {
158 kex->session_id_len = 20;
159 kex->session_id = xmalloc(kex->session_id_len);
160 memcpy(kex->session_id, hash, kex->session_id_len);
161 }
162
163 /* sign H */
164 /* XXX hashlen depends on KEX */
165 PRIVSEP(key_sign(server_host_key, &signature, &slen, hash, 20));
166
167 /* destroy_sensitive_data(); */
168
169 /* send server hostkey, DH pubkey 'f' and singed H */
170 debug("SSH2_MSG_KEX_DH_GEX_REPLY sent");
171 packet_start(SSH2_MSG_KEX_DH_GEX_REPLY);
172 packet_put_string(server_host_key_blob, sbloblen);
173 packet_put_bignum2(dh->pub_key); /* f */
174 packet_put_string(signature, slen);
175 packet_send();
176
177 xfree(signature);
178 xfree(server_host_key_blob);
179 /* have keys, free DH */
180 DH_free(dh);
181
182 kex_derive_keys(kex, hash, shared_secret);
183 BN_clear_free(shared_secret);
184
185 kex_finish(kex);
186}
diff --git a/ssh-keyscan.c b/ssh-keyscan.c
index 8c14d6d26..5b4eb82d1 100644
--- a/ssh-keyscan.c
+++ b/ssh-keyscan.c
@@ -7,7 +7,7 @@
7 */ 7 */
8 8
9#include "includes.h" 9#include "includes.h"
10RCSID("$OpenBSD: ssh-keyscan.c,v 1.40 2002/07/06 17:47:58 stevesk Exp $"); 10RCSID("$OpenBSD: ssh-keyscan.c,v 1.41 2003/02/16 17:09:57 markus Exp $");
11 11
12#include "openbsd-compat/sys-queue.h" 12#include "openbsd-compat/sys-queue.h"
13 13
@@ -354,6 +354,8 @@ keygrab_ssh2(con *c)
354 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA? 354 myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = c->c_keytype == KT_DSA?
355 "ssh-dss": "ssh-rsa"; 355 "ssh-dss": "ssh-rsa";
356 c->c_kex = kex_setup(myproposal); 356 c->c_kex = kex_setup(myproposal);
357 c->c_kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
358 c->c_kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
357 c->c_kex->verify_host_key = hostjump; 359 c->c_kex->verify_host_key = hostjump;
358 360
359 if (!(j = setjmp(kexjmp))) { 361 if (!(j = setjmp(kexjmp))) {
diff --git a/sshconnect2.c b/sshconnect2.c
index de33e142b..81d1b91c7 100644
--- a/sshconnect2.c
+++ b/sshconnect2.c
@@ -23,7 +23,7 @@
23 */ 23 */
24 24
25#include "includes.h" 25#include "includes.h"
26RCSID("$OpenBSD: sshconnect2.c,v 1.110 2002/12/19 00:07:02 djm Exp $"); 26RCSID("$OpenBSD: sshconnect2.c,v 1.111 2003/02/16 17:09:57 markus Exp $");
27 27
28#include "ssh.h" 28#include "ssh.h"
29#include "ssh2.h" 29#include "ssh2.h"
@@ -110,6 +110,8 @@ ssh_kex2(char *host, struct sockaddr *hostaddr)
110 110
111 /* start key exchange */ 111 /* start key exchange */
112 kex = kex_setup(myproposal); 112 kex = kex_setup(myproposal);
113 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_client;
114 kex->kex[KEX_DH_GEX_SHA1] = kexgex_client;
113 kex->client_version_string=client_version_string; 115 kex->client_version_string=client_version_string;
114 kex->server_version_string=server_version_string; 116 kex->server_version_string=server_version_string;
115 kex->verify_host_key=&verify_host_key_callback; 117 kex->verify_host_key=&verify_host_key_callback;
diff --git a/sshd.c b/sshd.c
index ca2d4d1bc..86441cff1 100644
--- a/sshd.c
+++ b/sshd.c
@@ -42,7 +42,7 @@
42 */ 42 */
43 43
44#include "includes.h" 44#include "includes.h"
45RCSID("$OpenBSD: sshd.c,v 1.262 2003/01/27 17:06:31 markus Exp $"); 45RCSID("$OpenBSD: sshd.c,v 1.263 2003/02/16 17:09:57 markus Exp $");
46 46
47#include <openssl/dh.h> 47#include <openssl/dh.h>
48#include <openssl/bn.h> 48#include <openssl/bn.h>
@@ -202,8 +202,8 @@ int *startup_pipes = NULL;
202int startup_pipe; /* in child */ 202int startup_pipe; /* in child */
203 203
204/* variables used for privilege separation */ 204/* variables used for privilege separation */
205extern struct monitor *pmonitor; 205int use_privsep;
206extern int use_privsep; 206struct monitor *pmonitor;
207 207
208/* Prototypes for various functions defined later in this file. */ 208/* Prototypes for various functions defined later in this file. */
209void destroy_sensitive_data(void); 209void destroy_sensitive_data(void);
@@ -1814,6 +1814,8 @@ do_ssh2_kex(void)
1814 1814
1815 /* start key exchange */ 1815 /* start key exchange */
1816 kex = kex_setup(myproposal); 1816 kex = kex_setup(myproposal);
1817 kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server;
1818 kex->kex[KEX_DH_GEX_SHA1] = kexgex_server;
1817 kex->server = 1; 1819 kex->server = 1;
1818 kex->client_version_string=client_version_string; 1820 kex->client_version_string=client_version_string;
1819 kex->server_version_string=server_version_string; 1821 kex->server_version_string=server_version_string;