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