Annotation of src/usr.bin/ssh/kex.c, Revision 1.26
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.26 ! markus 26: RCSID("$OpenBSD: kex.c,v 1.25 2001/03/29 21:17:39 markus Exp $");
1.18 markus 27:
28: #include <openssl/crypto.h>
1.1 markus 29:
30: #include "ssh2.h"
31: #include "xmalloc.h"
32: #include "buffer.h"
33: #include "bufaux.h"
1.7 markus 34: #include "packet.h"
1.1 markus 35: #include "compat.h"
1.18 markus 36: #include "cipher.h"
1.1 markus 37: #include "kex.h"
1.13 markus 38: #include "key.h"
1.18 markus 39: #include "log.h"
1.21 markus 40: #include "mac.h"
1.23 markus 41: #include "match.h"
1.26 ! markus 42: #include "dispatch.h"
1.1 markus 43:
1.7 markus 44: #define KEX_COOKIE_LEN 16
45:
1.26 ! markus 46: void kex_kexinit_finish(Kex *kex);
! 47: void kex_choose_conf(Kex *k);
! 48:
! 49: /* put algorithm proposal into buffer */
! 50: void
! 51: kex_prop2buf(Buffer *b, char *proposal[PROPOSAL_MAX])
1.1 markus 52: {
53: u_int32_t rand = 0;
54: int i;
1.26 ! markus 55:
! 56: buffer_clear(b);
1.7 markus 57: for (i = 0; i < KEX_COOKIE_LEN; i++) {
1.1 markus 58: if (i % 4 == 0)
59: rand = arc4random();
1.26 ! markus 60: buffer_put_char(b, rand & 0xff);
1.1 markus 61: rand >>= 8;
62: }
63: for (i = 0; i < PROPOSAL_MAX; i++)
1.26 ! markus 64: buffer_put_cstring(b, proposal[i]);
! 65: buffer_put_char(b, 0); /* first_kex_packet_follows */
! 66: buffer_put_int(b, 0); /* uint32 reserved */
1.1 markus 67: }
68:
1.26 ! markus 69: /* parse buffer and return algorithm proposal */
! 70: char **
! 71: kex_buf2prop(Buffer *raw)
1.7 markus 72: {
1.26 ! markus 73: Buffer b;
1.7 markus 74: int i;
1.26 ! markus 75: char **proposal;
1.7 markus 76:
1.26 ! markus 77: proposal = xmalloc(PROPOSAL_MAX * sizeof(char *));
1.7 markus 78:
1.26 ! markus 79: buffer_init(&b);
! 80: buffer_append(&b, buffer_ptr(raw), buffer_len(raw));
1.7 markus 81: /* skip cookie */
82: for (i = 0; i < KEX_COOKIE_LEN; i++)
1.26 ! markus 83: buffer_get_char(&b);
1.7 markus 84: /* extract kex init proposal strings */
85: for (i = 0; i < PROPOSAL_MAX; i++) {
1.26 ! markus 86: proposal[i] = buffer_get_string(&b,NULL);
! 87: debug2("kex_parse_kexinit: %s", proposal[i]);
1.7 markus 88: }
1.26 ! markus 89: /* first kex follows / reserved */
! 90: i = buffer_get_char(&b);
! 91: debug2("kex_parse_kexinit: first_kex_follows %d ", i);
! 92: i = buffer_get_int(&b);
! 93: debug2("kex_parse_kexinit: reserved %d ", i);
! 94: buffer_free(&b);
! 95: return proposal;
1.1 markus 96: }
97:
98: void
1.26 ! markus 99: kex_prop_free(char **proposal)
1.1 markus 100: {
101: int i;
1.26 ! markus 102:
! 103: for (i = 0; i < PROPOSAL_MAX; i++)
! 104: xfree(proposal[i]);
! 105: xfree(proposal);
1.1 markus 106: }
107:
1.26 ! markus 108: void
! 109: kex_protocol_error(int type, int plen, void *ctxt)
1.1 markus 110: {
1.26 ! markus 111: error("Hm, kex protocol error: type %d plen %d", type, plen);
! 112: }
1.1 markus 113:
1.26 ! markus 114: void
! 115: kex_send_newkeys(void)
! 116: {
! 117: packet_start(SSH2_MSG_NEWKEYS);
! 118: packet_send();
! 119: /* packet_write_wait(); */
! 120: debug("SSH2_MSG_NEWKEYS sent");
! 121: }
1.1 markus 122:
1.26 ! markus 123: void
! 124: kex_input_newkeys(int type, int plen, void *ctxt)
! 125: {
! 126: Kex *kex = ctxt;
! 127: int i;
1.19 stevesk 128:
1.26 ! markus 129: debug("SSH2_MSG_NEWKEYS received");
! 130: kex->newkeys = 1;
! 131: for (i = 30; i <= 49; i++)
! 132: dispatch_set(i, &kex_protocol_error);
! 133: buffer_clear(&kex->peer);
! 134: buffer_clear(&kex->my);
! 135: kex->flags &= ~KEX_INIT_SENT;
! 136: }
1.1 markus 137:
1.26 ! markus 138: void
! 139: kex_send_kexinit(Kex *kex)
! 140: {
! 141: packet_start(SSH2_MSG_KEXINIT);
! 142: packet_put_raw(buffer_ptr(&kex->my), buffer_len(&kex->my));
! 143: packet_send();
! 144: debug("SSH2_MSG_KEXINIT sent");
! 145: kex->flags |= KEX_INIT_SENT;
1.1 markus 146: }
147:
1.26 ! markus 148: void
! 149: kex_input_kexinit(int type, int plen, void *ctxt)
1.11 provos 150: {
1.26 ! markus 151: char *ptr;
! 152: int dlen;
! 153: Kex *kex = (Kex *)ctxt;
1.11 provos 154:
1.26 ! markus 155: dispatch_set(SSH2_MSG_KEXINIT, &kex_protocol_error);
! 156: debug("SSH2_MSG_KEXINIT received");
1.11 provos 157:
1.26 ! markus 158: ptr = packet_get_raw(&dlen);
! 159: buffer_append(&kex->peer, ptr, dlen);
1.19 stevesk 160:
1.26 ! markus 161: kex_kexinit_finish(kex);
! 162: }
1.11 provos 163:
1.26 ! markus 164: Kex *
! 165: kex_start(char *proposal[PROPOSAL_MAX])
! 166: {
! 167: Kex *kex;
! 168: int i;
1.11 provos 169:
1.26 ! markus 170: kex = xmalloc(sizeof(*kex));
! 171: memset(kex, 0, sizeof(*kex));
! 172: buffer_init(&kex->peer);
! 173: buffer_init(&kex->my);
! 174: kex_prop2buf(&kex->my, proposal);
! 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;
1.11 provos 185: }
186:
1.26 ! markus 187: void
! 188: kex_kexinit_finish(Kex *kex)
1.1 markus 189: {
1.26 ! markus 190: if (!(kex->flags & KEX_INIT_SENT))
! 191: kex_send_kexinit(kex);
1.1 markus 192:
1.26 ! markus 193: kex_choose_conf(kex);
1.1 markus 194:
1.26 ! markus 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);
1.1 markus 204: }
205: }
206:
207: void
208: choose_enc(Enc *enc, char *client, char *server)
209: {
1.23 markus 210: char *name = match_list(client, server, NULL);
1.1 markus 211: if (name == NULL)
212: fatal("no matching cipher found: client %s server %s", client, server);
1.12 markus 213: enc->cipher = cipher_by_name(name);
214: if (enc->cipher == NULL)
215: fatal("matching cipher is not supported: %s", name);
1.1 markus 216: enc->name = name;
217: enc->enabled = 0;
218: enc->iv = NULL;
219: enc->key = NULL;
220: }
221: void
222: choose_mac(Mac *mac, char *client, char *server)
223: {
1.23 markus 224: char *name = match_list(client, server, NULL);
1.1 markus 225: if (name == NULL)
226: fatal("no matching mac found: client %s server %s", client, server);
1.21 markus 227: if (mac_init(mac, name) < 0)
1.1 markus 228: fatal("unsupported mac %s", name);
1.21 markus 229: /* truncate the key */
230: if (datafellows & SSH_BUG_HMAC)
231: mac->key_len = 16;
1.1 markus 232: mac->name = name;
233: mac->key = NULL;
234: mac->enabled = 0;
235: }
236: void
237: choose_comp(Comp *comp, char *client, char *server)
238: {
1.23 markus 239: char *name = match_list(client, server, NULL);
1.1 markus 240: if (name == NULL)
241: fatal("no matching comp found: client %s server %s", client, server);
242: if (strcmp(name, "zlib") == 0) {
243: comp->type = 1;
244: } else if (strcmp(name, "none") == 0) {
245: comp->type = 0;
246: } else {
247: fatal("unsupported comp %s", name);
248: }
249: comp->name = name;
250: }
251: void
252: choose_kex(Kex *k, char *client, char *server)
253: {
1.23 markus 254: k->name = match_list(client, server, NULL);
1.1 markus 255: if (k->name == NULL)
256: fatal("no kex alg");
1.11 provos 257: if (strcmp(k->name, KEX_DH1) == 0) {
258: k->kex_type = DH_GRP1_SHA1;
259: } else if (strcmp(k->name, KEX_DHGEX) == 0) {
260: k->kex_type = DH_GEX_SHA1;
261: } else
1.1 markus 262: fatal("bad kex alg %s", k->name);
263: }
264: void
265: choose_hostkeyalg(Kex *k, char *client, char *server)
266: {
1.23 markus 267: char *hostkeyalg = match_list(client, server, NULL);
1.13 markus 268: if (hostkeyalg == NULL)
1.1 markus 269: fatal("no hostkey alg");
1.13 markus 270: k->hostkey_type = key_type_from_name(hostkeyalg);
271: if (k->hostkey_type == KEY_UNSPEC)
272: fatal("bad hostkey alg '%s'", hostkeyalg);
1.17 markus 273: xfree(hostkeyalg);
1.1 markus 274: }
275:
1.26 ! markus 276: void
! 277: kex_choose_conf(Kex *k)
1.1 markus 278: {
1.26 ! markus 279: char **my, **peer;
! 280: char **cprop, **sprop;
1.1 markus 281: int mode;
282: int ctos; /* direction: if true client-to-server */
283: int need;
284:
1.26 ! markus 285: my = kex_buf2prop(&k->my);
! 286: peer = kex_buf2prop(&k->peer);
! 287:
! 288: if (k->server) {
! 289: cprop=peer;
! 290: sprop=my;
! 291: } else {
! 292: cprop=my;
! 293: sprop=peer;
! 294: }
1.1 markus 295:
296: for (mode = 0; mode < MODE_MAX; mode++) {
297: int nenc, nmac, ncomp;
298: ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
299: nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
300: nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
301: ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
302: choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
303: choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
304: choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
1.2 markus 305: debug("kex: %s %s %s %s",
1.1 markus 306: ctos ? "client->server" : "server->client",
307: k->enc[mode].name,
308: k->mac[mode].name,
309: k->comp[mode].name);
310: }
311: choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
312: choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
313: sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
314: need = 0;
315: for (mode = 0; mode < MODE_MAX; mode++) {
1.12 markus 316: if (need < k->enc[mode].cipher->key_len)
317: need = k->enc[mode].cipher->key_len;
318: if (need < k->enc[mode].cipher->block_size)
319: need = k->enc[mode].cipher->block_size;
1.1 markus 320: if (need < k->mac[mode].key_len)
321: need = k->mac[mode].key_len;
322: }
1.7 markus 323: /* XXX need runden? */
1.1 markus 324: k->we_need = need;
1.26 ! markus 325:
! 326: kex_prop_free(my);
! 327: kex_prop_free(peer);
! 328:
! 329: }
! 330:
! 331: u_char *
! 332: derive_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;
1.1 markus 366: }
367:
1.23 markus 368: #define NKEYS 6
1.26 ! markus 369: void
1.15 markus 370: kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
1.1 markus 371: {
372: int i;
373: int mode;
374: int ctos;
1.15 markus 375: u_char *keys[NKEYS];
1.1 markus 376:
377: for (i = 0; i < NKEYS; i++)
378: keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
379:
380: for (mode = 0; mode < MODE_MAX; mode++) {
381: ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
382: k->enc[mode].iv = keys[ctos ? 0 : 1];
383: k->enc[mode].key = keys[ctos ? 2 : 3];
384: k->mac[mode].key = keys[ctos ? 4 : 5];
385: }
386: }
1.26 ! markus 387:
! 388: #if defined(DEBUG_KEX) || defined(DEBUG_KEXDH)
! 389: void
! 390: dump_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