]> andersk Git - openssh.git/blame - kex.c
- OpenBSD CVS updates:
[openssh.git] / kex.c
CommitLineData
7e7327a1 1/*
2 * Copyright (c) 2000 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 * 3. All advertising materials mentioning features or use of this software
13 * must display the following acknowledgement:
14 * This product includes software developed by Markus Friedl.
15 * 4. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "includes.h"
31RCSID("$Id$");
32
33#include "ssh.h"
34#include "ssh2.h"
35#include "xmalloc.h"
36#include "buffer.h"
37#include "bufaux.h"
38#include "cipher.h"
39#include "compat.h"
40
41#if HAVE_OPENSSL
42# include <openssl/bn.h>
43# include <openssl/dh.h>
44# include <openssl/crypto.h>
45# include <openssl/bio.h>
7e7327a1 46# include <openssl/pem.h>
47#endif /* HAVE_OPENSSL */
48#if HAVE_SSL
49# include <ssl/bn.h>
50# include <ssl/dh.h>
51# include <ssl/crypto.h>
52# include <ssl/bio.h>
7e7327a1 53# include <ssl/pem.h>
54#endif /* HAVE_SSL */
55
7e7327a1 56#include "kex.h"
57
58Buffer *
59kex_init(char *myproposal[PROPOSAL_MAX])
60{
61 char c = 0;
62 unsigned char cookie[16];
63 u_int32_t rand = 0;
64 int i;
65 Buffer *ki = xmalloc(sizeof(*ki));
66 for (i = 0; i < 16; i++) {
67 if (i % 4 == 0)
68 rand = arc4random();
69 cookie[i] = rand & 0xff;
70 rand >>= 8;
71 }
72 buffer_init(ki);
73 buffer_append(ki, (char *)cookie, sizeof cookie);
74 for (i = 0; i < PROPOSAL_MAX; i++)
75 buffer_put_cstring(ki, myproposal[i]);
76 buffer_append(ki, &c, 1); /* boolean first_kex_packet_follows */
77 buffer_put_int(ki, 0); /* uint32 0 (reserved for future extension) */
78 return ki;
79}
80
81/* diffie-hellman-group1-sha1 */
82
a8be9f80 83int
84dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
85{
86 int i;
87 int n = BN_num_bits(dh_pub);
88 int bits_set = 0;
89
90 /* we only accept g==2 */
91 if (!BN_is_word(dh->g, 2)) {
92 log("invalid DH base != 2");
93 return 0;
94 }
95 if (dh_pub->neg) {
96 log("invalid public DH value: negativ");
97 return 0;
98 }
99 for (i = 0; i <= n; i++)
100 if (BN_is_bit_set(dh_pub, i))
101 bits_set++;
102 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
103
104 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
105 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
106 return 1;
107 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
108 return 0;
109}
110
7e7327a1 111DH *
a8be9f80 112dh_new_group1()
7e7327a1 113{
114 static char *group1 =
115 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
116 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
117 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
118 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
119 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
120 "FFFFFFFF" "FFFFFFFF";
121 DH *dh;
a8be9f80 122 int ret, tries = 0;
7e7327a1 123 dh = DH_new();
124 if(dh == NULL)
125 fatal("DH_new");
a8be9f80 126 ret = BN_hex2bn(&dh->p, group1);
7e7327a1 127 if(ret<0)
128 fatal("BN_hex2bn");
129 dh->g = BN_new();
130 if(dh->g == NULL)
131 fatal("DH_new g");
a8be9f80 132 BN_set_word(dh->g, 2);
133 do {
134 if (DH_generate_key(dh) == 0)
135 fatal("DH_generate_key");
136 if (tries++ > 10)
137 fatal("dh_new_group1: too many bad keys: giving up");
138 } while (!dh_pub_is_valid(dh, dh->pub_key));
7e7327a1 139 return dh;
140}
141
142void
143bignum_print(BIGNUM *b)
144{
145 BN_print_fp(stderr,b);
146}
147
148void
149dump_digest(unsigned char *digest, int len)
150{
151 int i;
152 for (i = 0; i< len; i++){
153 fprintf(stderr, "%02x", digest[i]);
154 if(i%2!=0)
155 fprintf(stderr, " ");
156 }
157 fprintf(stderr, "\n");
158}
159
160unsigned char *
161kex_hash(
162 char *client_version_string,
163 char *server_version_string,
164 char *ckexinit, int ckexinitlen,
165 char *skexinit, int skexinitlen,
166 char *serverhostkeyblob, int sbloblen,
167 BIGNUM *client_dh_pub,
168 BIGNUM *server_dh_pub,
169 BIGNUM *shared_secret)
170{
171 Buffer b;
172 static unsigned char digest[EVP_MAX_MD_SIZE];
173 EVP_MD *evp_md = EVP_sha1();
174 EVP_MD_CTX md;
175
176 buffer_init(&b);
177 buffer_put_string(&b, client_version_string, strlen(client_version_string));
178 buffer_put_string(&b, server_version_string, strlen(server_version_string));
179
180 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
181 buffer_put_int(&b, ckexinitlen+1);
182 buffer_put_char(&b, SSH2_MSG_KEXINIT);
183 buffer_append(&b, ckexinit, ckexinitlen);
184 buffer_put_int(&b, skexinitlen+1);
185 buffer_put_char(&b, SSH2_MSG_KEXINIT);
186 buffer_append(&b, skexinit, skexinitlen);
187
188 buffer_put_string(&b, serverhostkeyblob, sbloblen);
189 buffer_put_bignum2(&b, client_dh_pub);
190 buffer_put_bignum2(&b, server_dh_pub);
191 buffer_put_bignum2(&b, shared_secret);
192
193#ifdef DEBUG_KEX
194 buffer_dump(&b);
195#endif
196
197 EVP_DigestInit(&md, evp_md);
198 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
199 EVP_DigestFinal(&md, digest, NULL);
200
201 buffer_free(&b);
202
203#ifdef DEBUG_KEX
204 dump_digest(digest, evp_md->md_size);
205#endif
206 return digest;
207}
208
209unsigned char *
210derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
211{
212 Buffer b;
213 EVP_MD *evp_md = EVP_sha1();
214 EVP_MD_CTX md;
215 char c = id;
216 int have;
217 int mdsz = evp_md->md_size;
218 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
219
220 buffer_init(&b);
221 buffer_put_bignum2(&b, shared_secret);
222
223 EVP_DigestInit(&md, evp_md);
224 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
225 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
226 EVP_DigestUpdate(&md, &c, 1); /* key id */
227 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
228 EVP_DigestFinal(&md, digest, NULL);
229
230 /* expand */
231 for (have = mdsz; need > have; have += mdsz) {
232 EVP_DigestInit(&md, evp_md);
233 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
234 EVP_DigestUpdate(&md, hash, mdsz);
235 EVP_DigestUpdate(&md, digest, have);
236 EVP_DigestFinal(&md, digest + have, NULL);
237 }
238 buffer_free(&b);
239#ifdef DEBUG_KEX
240 fprintf(stderr, "Digest '%c'== ", c);
241 dump_digest(digest, need);
242#endif
243 return digest;
244}
245
246#define NKEYS 6
247
248#define MAX_PROP 20
249#define SEP ","
250
251char *
252get_match(char *client, char *server)
253{
254 char *sproposals[MAX_PROP];
255 char *p;
256 int i, j, nproposals;
257
258 for ((p = strtok(server, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
259 if (i < MAX_PROP)
260 sproposals[i] = p;
261 else
262 break;
263 }
264 nproposals = i;
265
266 for ((p = strtok(client, SEP)), i=0; p; (p = strtok(NULL, SEP)), i++) {
267 for (j = 0; j < nproposals; j++)
268 if (strcmp(p, sproposals[j]) == 0)
269 return xstrdup(p);
270 }
271 return NULL;
272}
273void
274choose_enc(Enc *enc, char *client, char *server)
275{
276 char *name = get_match(client, server);
277 if (name == NULL)
278 fatal("no matching cipher found: client %s server %s", client, server);
279 enc->type = cipher_number(name);
280
281 switch (enc->type) {
282 case SSH_CIPHER_3DES_CBC:
283 enc->key_len = 24;
284 enc->iv_len = 8;
285 enc->block_size = 8;
286 break;
287 case SSH_CIPHER_BLOWFISH_CBC:
288 case SSH_CIPHER_CAST128_CBC:
289 enc->key_len = 16;
290 enc->iv_len = 8;
291 enc->block_size = 8;
292 break;
293 case SSH_CIPHER_ARCFOUR:
294 enc->key_len = 16;
295 enc->iv_len = 0;
296 enc->block_size = 8;
297 break;
298 default:
299 fatal("unsupported cipher %s", name);
300 }
301 enc->name = name;
302 enc->enabled = 0;
303 enc->iv = NULL;
304 enc->key = NULL;
305}
306void
307choose_mac(Mac *mac, char *client, char *server)
308{
309 char *name = get_match(client, server);
310 if (name == NULL)
311 fatal("no matching mac found: client %s server %s", client, server);
312 if (strcmp(name, "hmac-md5") == 0) {
313 mac->md = EVP_md5();
314 } else if (strcmp(name, "hmac-sha1") == 0) {
315 mac->md = EVP_sha1();
316 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
317 mac->md = EVP_ripemd160();
318 } else {
319 fatal("unsupported mac %s", name);
320 }
321 mac->name = name;
322 mac->mac_len = mac->md->md_size;
323 mac->key_len = datafellows ? 16 : mac->mac_len;
324 mac->key = NULL;
325 mac->enabled = 0;
326}
327void
328choose_comp(Comp *comp, char *client, char *server)
329{
330 char *name = get_match(client, server);
331 if (name == NULL)
332 fatal("no matching comp found: client %s server %s", client, server);
333 if (strcmp(name, "zlib") == 0) {
334 comp->type = 1;
335 } else if (strcmp(name, "none") == 0) {
336 comp->type = 0;
337 } else {
338 fatal("unsupported comp %s", name);
339 }
340 comp->name = name;
341}
342void
343choose_kex(Kex *k, char *client, char *server)
344{
345 k->name = get_match(client, server);
346 if (k->name == NULL)
347 fatal("no kex alg");
348 if (strcmp(k->name, KEX_DH1) != 0)
349 fatal("bad kex alg %s", k->name);
350}
351void
352choose_hostkeyalg(Kex *k, char *client, char *server)
353{
354 k->hostkeyalg = get_match(client, server);
355 if (k->hostkeyalg == NULL)
356 fatal("no hostkey alg");
357 if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
358 fatal("bad hostkey alg %s", k->hostkeyalg);
359}
360
361Kex *
362kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
363{
364 int i;
365 int mode;
366 int ctos; /* direction: if true client-to-server */
367 int need;
368 Kex *k;
369
370 k = xmalloc(sizeof(*k));
371 memset(k, 0, sizeof(*k));
372 k->server = server;
373
374 for (mode = 0; mode < MODE_MAX; mode++) {
375 int nenc, nmac, ncomp;
376 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
377 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
378 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
379 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
380 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
381 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
382 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
a8be9f80 383 debug("kex: %s %s %s %s",
7e7327a1 384 ctos ? "client->server" : "server->client",
385 k->enc[mode].name,
386 k->mac[mode].name,
387 k->comp[mode].name);
388 }
389 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
390 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
391 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
392 for (i = 0; i < PROPOSAL_MAX; i++) {
393 xfree(cprop[i]);
394 xfree(sprop[i]);
395 }
396 need = 0;
397 for (mode = 0; mode < MODE_MAX; mode++) {
398 if (need < k->enc[mode].key_len)
399 need = k->enc[mode].key_len;
400 if (need < k->enc[mode].iv_len)
401 need = k->enc[mode].iv_len;
402 if (need < k->mac[mode].key_len)
403 need = k->mac[mode].key_len;
404 }
405 /* need runden? */
406#define WE_NEED 32
407 k->we_need = WE_NEED;
408 k->we_need = need;
409 return k;
410}
411
412int
413kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
414{
415 int i;
416 int mode;
417 int ctos;
418 unsigned char *keys[NKEYS];
419
420 for (i = 0; i < NKEYS; i++)
421 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
422
423 for (mode = 0; mode < MODE_MAX; mode++) {
424 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
425 k->enc[mode].iv = keys[ctos ? 0 : 1];
426 k->enc[mode].key = keys[ctos ? 2 : 3];
427 k->mac[mode].key = keys[ctos ? 4 : 5];
428 }
429 return 0;
430}
This page took 0.106031 seconds and 5 git commands to generate.