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