Annotation of src/usr.bin/ssh/kex.c, Revision 1.25
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: *
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"
1.25 ! markus 26: RCSID("$OpenBSD: kex.c,v 1.24 2001/03/28 21:59:40 provos Exp $");
1.18 markus 27:
28: #include <openssl/crypto.h>
29: #include <openssl/bio.h>
30: #include <openssl/bn.h>
31: #include <openssl/pem.h>
1.1 markus 32:
33: #include "ssh2.h"
34: #include "xmalloc.h"
35: #include "buffer.h"
36: #include "bufaux.h"
1.7 markus 37: #include "packet.h"
1.1 markus 38: #include "compat.h"
1.18 markus 39: #include "cipher.h"
1.1 markus 40: #include "kex.h"
1.13 markus 41: #include "key.h"
1.18 markus 42: #include "log.h"
1.21 markus 43: #include "mac.h"
1.23 markus 44: #include "match.h"
1.1 markus 45:
1.7 markus 46: #define KEX_COOKIE_LEN 16
47:
1.1 markus 48: Buffer *
49: kex_init(char *myproposal[PROPOSAL_MAX])
50: {
1.7 markus 51: int first_kex_packet_follows = 0;
1.15 markus 52: u_char cookie[KEX_COOKIE_LEN];
1.1 markus 53: u_int32_t rand = 0;
54: int i;
55: Buffer *ki = xmalloc(sizeof(*ki));
1.7 markus 56: for (i = 0; i < KEX_COOKIE_LEN; i++) {
1.1 markus 57: if (i % 4 == 0)
58: rand = arc4random();
59: cookie[i] = rand & 0xff;
60: rand >>= 8;
61: }
62: buffer_init(ki);
63: buffer_append(ki, (char *)cookie, sizeof cookie);
64: for (i = 0; i < PROPOSAL_MAX; i++)
65: buffer_put_cstring(ki, myproposal[i]);
1.7 markus 66: buffer_put_char(ki, first_kex_packet_follows);
67: buffer_put_int(ki, 0); /* uint32 reserved */
1.1 markus 68: return ki;
69: }
70:
1.7 markus 71: /* send kexinit, parse and save reply */
72: void
73: kex_exchange_kexinit(
74: Buffer *my_kexinit, Buffer *peer_kexint,
75: char *peer_proposal[PROPOSAL_MAX])
76: {
77: int i;
78: char *ptr;
79: int plen;
80:
81: debug("send KEXINIT");
82: packet_start(SSH2_MSG_KEXINIT);
1.19 stevesk 83: packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
1.7 markus 84: packet_send();
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 */
99: for (i = 0; i < KEX_COOKIE_LEN; i++)
100: packet_get_char();
101: /* extract kex init proposal strings */
102: for (i = 0; i < PROPOSAL_MAX; i++) {
103: peer_proposal[i] = packet_get_string(NULL);
104: debug("got kexinit: %s", peer_proposal[i]);
105: }
106: /* first kex follow / reserved */
107: i = packet_get_char();
108: debug("first kex follow: %d ", i);
109: i = packet_get_int();
110: debug("reserved: %d ", i);
111: packet_done();
112: debug("done");
1.1 markus 113: }
114:
1.20 itojun 115: #ifdef DEBUG_KEX
1.1 markus 116: void
1.15 markus 117: dump_digest(u_char *digest, int len)
1.1 markus 118: {
119: int i;
1.5 markus 120: for (i = 0; i< len; i++){
121: fprintf(stderr, "%02x", digest[i]);
1.1 markus 122: if(i%2!=0)
123: fprintf(stderr, " ");
124: }
1.5 markus 125: fprintf(stderr, "\n");
1.1 markus 126: }
1.20 itojun 127: #endif
1.1 markus 128:
1.15 markus 129: u_char *
1.1 markus 130: kex_hash(
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: {
140: Buffer b;
1.15 markus 141: static u_char digest[EVP_MAX_MD_SIZE];
1.1 markus 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);
1.19 stevesk 161:
1.1 markus 162: #ifdef DEBUG_KEX
163: buffer_dump(&b);
164: #endif
165:
166: EVP_DigestInit(&md, evp_md);
167: EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
168: EVP_DigestFinal(&md, digest, NULL);
169:
170: buffer_free(&b);
171:
172: #ifdef DEBUG_KEX
1.5 markus 173: dump_digest(digest, evp_md->md_size);
1.1 markus 174: #endif
175: return digest;
176: }
177:
1.15 markus 178: u_char *
1.11 provos 179: kex_hash_gex(
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,
1.24 provos 185: int min, int wantbits, int max, BIGNUM *prime, BIGNUM *gen,
1.11 provos 186: BIGNUM *client_dh_pub,
187: BIGNUM *server_dh_pub,
188: BIGNUM *shared_secret)
189: {
190: Buffer b;
1.15 markus 191: static u_char digest[EVP_MAX_MD_SIZE];
1.11 provos 192: EVP_MD *evp_md = EVP_sha1();
193: EVP_MD_CTX md;
194:
195: buffer_init(&b);
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);
1.24 provos 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: }
1.11 provos 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);
1.19 stevesk 220:
1.11 provos 221: #ifdef DEBUG_KEX
222: buffer_dump(&b);
223: #endif
224:
225: EVP_DigestInit(&md, evp_md);
226: EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
227: EVP_DigestFinal(&md, digest, NULL);
228:
229: buffer_free(&b);
230:
231: #ifdef DEBUG_KEX
232: dump_digest(digest, evp_md->md_size);
233: #endif
234: return digest;
235: }
236:
1.15 markus 237: u_char *
238: derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)
1.1 markus 239: {
240: Buffer b;
241: EVP_MD *evp_md = EVP_sha1();
242: EVP_MD_CTX md;
243: char c = id;
244: int have;
245: int mdsz = evp_md->md_size;
1.15 markus 246: u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
1.1 markus 247:
248: buffer_init(&b);
249: buffer_put_bignum2(&b, shared_secret);
250:
251: EVP_DigestInit(&md, evp_md);
252: EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
253: EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
254: EVP_DigestUpdate(&md, &c, 1); /* key id */
255: EVP_DigestUpdate(&md, hash, mdsz); /* session id */
256: EVP_DigestFinal(&md, digest, NULL);
257:
258: /* expand */
259: for (have = mdsz; need > have; have += mdsz) {
260: EVP_DigestInit(&md, evp_md);
261: EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
262: EVP_DigestUpdate(&md, hash, mdsz);
263: EVP_DigestUpdate(&md, digest, have);
264: EVP_DigestFinal(&md, digest + have, NULL);
265: }
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: }
273:
274: void
275: choose_enc(Enc *enc, char *client, char *server)
276: {
1.23 markus 277: char *name = match_list(client, server, NULL);
1.1 markus 278: if (name == NULL)
279: fatal("no matching cipher found: client %s server %s", client, server);
1.12 markus 280: enc->cipher = cipher_by_name(name);
281: if (enc->cipher == NULL)
282: fatal("matching cipher is not supported: %s", name);
1.1 markus 283: enc->name = name;
284: enc->enabled = 0;
285: enc->iv = NULL;
286: enc->key = NULL;
287: }
288: void
289: choose_mac(Mac *mac, char *client, char *server)
290: {
1.23 markus 291: char *name = match_list(client, server, NULL);
1.1 markus 292: if (name == NULL)
293: fatal("no matching mac found: client %s server %s", client, server);
1.21 markus 294: if (mac_init(mac, name) < 0)
1.1 markus 295: fatal("unsupported mac %s", name);
1.21 markus 296: /* truncate the key */
297: if (datafellows & SSH_BUG_HMAC)
298: mac->key_len = 16;
1.1 markus 299: mac->name = name;
300: mac->key = NULL;
301: mac->enabled = 0;
302: }
303: void
304: choose_comp(Comp *comp, char *client, char *server)
305: {
1.23 markus 306: char *name = match_list(client, server, NULL);
1.1 markus 307: if (name == NULL)
308: fatal("no matching comp found: client %s server %s", client, server);
309: if (strcmp(name, "zlib") == 0) {
310: comp->type = 1;
311: } else if (strcmp(name, "none") == 0) {
312: comp->type = 0;
313: } else {
314: fatal("unsupported comp %s", name);
315: }
316: comp->name = name;
317: }
318: void
319: choose_kex(Kex *k, char *client, char *server)
320: {
1.23 markus 321: k->name = match_list(client, server, NULL);
1.1 markus 322: if (k->name == NULL)
323: fatal("no kex alg");
1.11 provos 324: if (strcmp(k->name, KEX_DH1) == 0) {
325: k->kex_type = DH_GRP1_SHA1;
326: } else if (strcmp(k->name, KEX_DHGEX) == 0) {
327: k->kex_type = DH_GEX_SHA1;
328: } else
1.1 markus 329: fatal("bad kex alg %s", k->name);
330: }
331: void
332: choose_hostkeyalg(Kex *k, char *client, char *server)
333: {
1.23 markus 334: char *hostkeyalg = match_list(client, server, NULL);
1.13 markus 335: if (hostkeyalg == NULL)
1.1 markus 336: fatal("no hostkey alg");
1.13 markus 337: k->hostkey_type = key_type_from_name(hostkeyalg);
338: if (k->hostkey_type == KEY_UNSPEC)
339: fatal("bad hostkey alg '%s'", hostkeyalg);
1.17 markus 340: xfree(hostkeyalg);
1.1 markus 341: }
342:
343: Kex *
344: kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
345: {
346: int mode;
347: int ctos; /* direction: if true client-to-server */
348: int need;
349: Kex *k;
350:
351: k = xmalloc(sizeof(*k));
352: memset(k, 0, sizeof(*k));
353: k->server = server;
354:
355: for (mode = 0; mode < MODE_MAX; mode++) {
356: int nenc, nmac, ncomp;
357: ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
358: nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
359: nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
360: ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
361: choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
362: choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
363: choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
1.2 markus 364: debug("kex: %s %s %s %s",
1.1 markus 365: ctos ? "client->server" : "server->client",
366: k->enc[mode].name,
367: k->mac[mode].name,
368: k->comp[mode].name);
369: }
370: choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
371: choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
372: sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
373: need = 0;
374: for (mode = 0; mode < MODE_MAX; mode++) {
1.12 markus 375: if (need < k->enc[mode].cipher->key_len)
376: need = k->enc[mode].cipher->key_len;
377: if (need < k->enc[mode].cipher->block_size)
378: need = k->enc[mode].cipher->block_size;
1.1 markus 379: if (need < k->mac[mode].key_len)
380: need = k->mac[mode].key_len;
381: }
1.7 markus 382: /* XXX need runden? */
1.1 markus 383: k->we_need = need;
384: return k;
385: }
386:
1.23 markus 387: #define NKEYS 6
1.1 markus 388: int
1.15 markus 389: kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
1.1 markus 390: {
391: int i;
392: int mode;
393: int ctos;
1.15 markus 394: u_char *keys[NKEYS];
1.1 markus 395:
396: for (i = 0; i < NKEYS; i++)
397: keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
398:
399: for (mode = 0; mode < MODE_MAX; mode++) {
400: ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
401: k->enc[mode].iv = keys[ctos ? 0 : 1];
402: k->enc[mode].key = keys[ctos ? 2 : 3];
403: k->mac[mode].key = keys[ctos ? 4 : 5];
404: }
405: return 0;
406: }