summaryrefslogtreecommitdiff
path: root/kex.c
diff options
context:
space:
mode:
Diffstat (limited to 'kex.c')
-rw-r--r--kex.c386
1 files changed, 192 insertions, 194 deletions
diff --git a/kex.c b/kex.c
index 576d4b56e..a0a5b46fe 100644
--- a/kex.c
+++ b/kex.c
@@ -23,12 +23,9 @@
23 */ 23 */
24 24
25#include "includes.h" 25#include "includes.h"
26RCSID("$OpenBSD: kex.c,v 1.25 2001/03/29 21:17:39 markus Exp $"); 26RCSID("$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
48Buffer * 46void kex_kexinit_finish(Kex *kex);
49kex_init(char *myproposal[PROPOSAL_MAX]) 47void kex_choose_conf(Kex *k);
48
49/* put algorithm proposal into buffer */
50void
51kex_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 */
72void 70char **
73kex_exchange_kexinit( 71kex_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
116void 98void
117dump_digest(u_char *digest, int len) 99kex_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
129u_char * 108void
130kex_hash( 109kex_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); 114void
167 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); 115kex_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); 123void
124kex_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
178u_char * 138void
179kex_hash_gex( 139kex_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 148void
222 buffer_dump(&b); 149kex_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
237u_char * 164Kex *
238derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret) 165kex_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 */ 187void
259 for (have = mdsz; need > have; have += mdsz) { 188kex_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
274void 207void
@@ -340,17 +273,25 @@ choose_hostkeyalg(Kex *k, char *client, char *server)
340 xfree(hostkeyalg); 273 xfree(hostkeyalg);
341} 274}
342 275
343Kex * 276void
344kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server) 277kex_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
331u_char *
332derive_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
388int 369void
389kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret) 370kex_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)
389void
390dump_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