2 * Copyright (c) 2000 Markus Friedl. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 RCSID("$OpenBSD: kex.c,v 1.14 2000/12/15 17:30:14 provos Exp $");
36 #include <openssl/bn.h>
37 #include <openssl/dh.h>
39 #include <openssl/crypto.h>
40 #include <openssl/bio.h>
41 #include <openssl/bn.h>
42 #include <openssl/dh.h>
43 #include <openssl/pem.h>
48 #define KEX_COOKIE_LEN 16
51 kex_init(char *myproposal[PROPOSAL_MAX])
53 int first_kex_packet_follows = 0;
54 unsigned char cookie[KEX_COOKIE_LEN];
57 Buffer *ki = xmalloc(sizeof(*ki));
58 for (i = 0; i < KEX_COOKIE_LEN; i++) {
61 cookie[i] = rand & 0xff;
65 buffer_append(ki, (char *)cookie, sizeof cookie);
66 for (i = 0; i < PROPOSAL_MAX; i++)
67 buffer_put_cstring(ki, myproposal[i]);
68 buffer_put_char(ki, first_kex_packet_follows);
69 buffer_put_int(ki, 0); /* uint32 reserved */
73 /* send kexinit, parse and save reply */
76 Buffer *my_kexinit, Buffer *peer_kexint,
77 char *peer_proposal[PROPOSAL_MAX])
83 debug("send KEXINIT");
84 packet_start(SSH2_MSG_KEXINIT);
85 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
91 * read and save raw KEXINIT payload in buffer. this is used during
92 * computation of the session_id and the session keys.
94 debug("wait KEXINIT");
95 packet_read_expect(&plen, SSH2_MSG_KEXINIT);
96 ptr = packet_get_raw(&plen);
97 buffer_append(peer_kexint, ptr, plen);
99 /* parse packet and save algorithm proposal */
101 for (i = 0; i < KEX_COOKIE_LEN; i++)
103 /* extract kex init proposal strings */
104 for (i = 0; i < PROPOSAL_MAX; i++) {
105 peer_proposal[i] = packet_get_string(NULL);
106 debug("got kexinit: %s", peer_proposal[i]);
108 /* first kex follow / reserved */
109 i = packet_get_char();
110 debug("first kex follow: %d ", i);
111 i = packet_get_int();
112 debug("reserved: %d ", i);
117 /* diffie-hellman-group1-sha1 */
120 dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
123 int n = BN_num_bits(dh_pub);
127 log("invalid public DH value: negativ");
130 for (i = 0; i <= n; i++)
131 if (BN_is_bit_set(dh_pub, i))
133 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
135 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
136 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
138 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
148 if (DH_generate_key(dh) == 0)
149 fatal("DH_generate_key");
151 fatal("dh_new_group1: too many bad keys: giving up");
152 } while (!dh_pub_is_valid(dh, dh->pub_key));
156 dh_new_group_asc(const char *gen, const char *modulus)
165 if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
166 fatal("BN_hex2bn p");
167 if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
168 fatal("BN_hex2bn g");
174 * This just returns the group, we still need to generate the exchange
179 dh_new_group(BIGNUM *gen, BIGNUM *modulus)
195 static char *gen = "2", *group1 =
196 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
197 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
198 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
199 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
200 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
201 "FFFFFFFF" "FFFFFFFF";
203 return (dh_new_group_asc(gen, group1));
207 dump_digest(unsigned char *digest, int len)
210 for (i = 0; i< len; i++){
211 fprintf(stderr, "%02x", digest[i]);
213 fprintf(stderr, " ");
215 fprintf(stderr, "\n");
220 char *client_version_string,
221 char *server_version_string,
222 char *ckexinit, int ckexinitlen,
223 char *skexinit, int skexinitlen,
224 char *serverhostkeyblob, int sbloblen,
225 BIGNUM *client_dh_pub,
226 BIGNUM *server_dh_pub,
227 BIGNUM *shared_secret)
230 static unsigned char digest[EVP_MAX_MD_SIZE];
231 EVP_MD *evp_md = EVP_sha1();
235 buffer_put_string(&b, client_version_string, strlen(client_version_string));
236 buffer_put_string(&b, server_version_string, strlen(server_version_string));
238 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
239 buffer_put_int(&b, ckexinitlen+1);
240 buffer_put_char(&b, SSH2_MSG_KEXINIT);
241 buffer_append(&b, ckexinit, ckexinitlen);
242 buffer_put_int(&b, skexinitlen+1);
243 buffer_put_char(&b, SSH2_MSG_KEXINIT);
244 buffer_append(&b, skexinit, skexinitlen);
246 buffer_put_string(&b, serverhostkeyblob, sbloblen);
247 buffer_put_bignum2(&b, client_dh_pub);
248 buffer_put_bignum2(&b, server_dh_pub);
249 buffer_put_bignum2(&b, shared_secret);
255 EVP_DigestInit(&md, evp_md);
256 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
257 EVP_DigestFinal(&md, digest, NULL);
262 dump_digest(digest, evp_md->md_size);
269 char *client_version_string,
270 char *server_version_string,
271 char *ckexinit, int ckexinitlen,
272 char *skexinit, int skexinitlen,
273 char *serverhostkeyblob, int sbloblen,
274 int minbits, BIGNUM *prime, BIGNUM *gen,
275 BIGNUM *client_dh_pub,
276 BIGNUM *server_dh_pub,
277 BIGNUM *shared_secret)
280 static unsigned char digest[EVP_MAX_MD_SIZE];
281 EVP_MD *evp_md = EVP_sha1();
285 buffer_put_string(&b, client_version_string, strlen(client_version_string));
286 buffer_put_string(&b, server_version_string, strlen(server_version_string));
288 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
289 buffer_put_int(&b, ckexinitlen+1);
290 buffer_put_char(&b, SSH2_MSG_KEXINIT);
291 buffer_append(&b, ckexinit, ckexinitlen);
292 buffer_put_int(&b, skexinitlen+1);
293 buffer_put_char(&b, SSH2_MSG_KEXINIT);
294 buffer_append(&b, skexinit, skexinitlen);
296 buffer_put_string(&b, serverhostkeyblob, sbloblen);
297 buffer_put_int(&b, minbits);
298 buffer_put_bignum2(&b, prime);
299 buffer_put_bignum2(&b, gen);
300 buffer_put_bignum2(&b, client_dh_pub);
301 buffer_put_bignum2(&b, server_dh_pub);
302 buffer_put_bignum2(&b, shared_secret);
308 EVP_DigestInit(&md, evp_md);
309 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
310 EVP_DigestFinal(&md, digest, NULL);
315 dump_digest(digest, evp_md->md_size);
321 derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
324 EVP_MD *evp_md = EVP_sha1();
328 int mdsz = evp_md->md_size;
329 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
332 buffer_put_bignum2(&b, shared_secret);
334 EVP_DigestInit(&md, evp_md);
335 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
336 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
337 EVP_DigestUpdate(&md, &c, 1); /* key id */
338 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
339 EVP_DigestFinal(&md, digest, NULL);
342 for (have = mdsz; need > have; have += mdsz) {
343 EVP_DigestInit(&md, evp_md);
344 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
345 EVP_DigestUpdate(&md, hash, mdsz);
346 EVP_DigestUpdate(&md, digest, have);
347 EVP_DigestFinal(&md, digest + have, NULL);
351 fprintf(stderr, "Digest '%c'== ", c);
352 dump_digest(digest, need);
363 get_match(char *client, char *server)
365 char *sproposals[MAX_PROP];
366 char *c, *s, *p, *ret, *cp, *sp;
367 int i, j, nproposals;
369 c = cp = xstrdup(client);
370 s = sp = xstrdup(server);
372 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
373 (p = strsep(&sp, SEP)), i++) {
381 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
382 (p = strsep(&cp, SEP)), i++) {
383 for (j = 0; j < nproposals; j++) {
384 if (strcmp(p, sproposals[j]) == 0) {
397 choose_enc(Enc *enc, char *client, char *server)
399 char *name = get_match(client, server);
401 fatal("no matching cipher found: client %s server %s", client, server);
402 enc->cipher = cipher_by_name(name);
403 if (enc->cipher == NULL)
404 fatal("matching cipher is not supported: %s", name);
411 choose_mac(Mac *mac, char *client, char *server)
413 char *name = get_match(client, server);
415 fatal("no matching mac found: client %s server %s", client, server);
416 if (strcmp(name, "hmac-md5") == 0) {
418 } else if (strcmp(name, "hmac-sha1") == 0) {
419 mac->md = EVP_sha1();
420 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
421 mac->md = EVP_ripemd160();
423 fatal("unsupported mac %s", name);
426 mac->mac_len = mac->md->md_size;
427 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
432 choose_comp(Comp *comp, char *client, char *server)
434 char *name = get_match(client, server);
436 fatal("no matching comp found: client %s server %s", client, server);
437 if (strcmp(name, "zlib") == 0) {
439 } else if (strcmp(name, "none") == 0) {
442 fatal("unsupported comp %s", name);
447 choose_kex(Kex *k, char *client, char *server)
449 k->name = get_match(client, server);
452 if (strcmp(k->name, KEX_DH1) == 0) {
453 k->kex_type = DH_GRP1_SHA1;
454 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
455 k->kex_type = DH_GEX_SHA1;
457 fatal("bad kex alg %s", k->name);
460 choose_hostkeyalg(Kex *k, char *client, char *server)
462 char *hostkeyalg = get_match(client, server);
463 if (hostkeyalg == NULL)
464 fatal("no hostkey alg");
465 k->hostkey_type = key_type_from_name(hostkeyalg);
466 if (k->hostkey_type == KEY_UNSPEC)
467 fatal("bad hostkey alg '%s'", hostkeyalg);
471 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
474 int ctos; /* direction: if true client-to-server */
478 k = xmalloc(sizeof(*k));
479 memset(k, 0, sizeof(*k));
482 for (mode = 0; mode < MODE_MAX; mode++) {
483 int nenc, nmac, ncomp;
484 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
485 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
486 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
487 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
488 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
489 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
490 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
491 debug("kex: %s %s %s %s",
492 ctos ? "client->server" : "server->client",
497 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
498 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
499 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
501 for (mode = 0; mode < MODE_MAX; mode++) {
502 if (need < k->enc[mode].cipher->key_len)
503 need = k->enc[mode].cipher->key_len;
504 if (need < k->enc[mode].cipher->block_size)
505 need = k->enc[mode].cipher->block_size;
506 if (need < k->mac[mode].key_len)
507 need = k->mac[mode].key_len;
509 /* XXX need runden? */
515 kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
520 unsigned char *keys[NKEYS];
522 for (i = 0; i < NKEYS; i++)
523 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
525 for (mode = 0; mode < MODE_MAX; mode++) {
526 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
527 k->enc[mode].iv = keys[ctos ? 0 : 1];
528 k->enc[mode].key = keys[ctos ? 2 : 3];
529 k->mac[mode].key = keys[ctos ? 4 : 5];