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.19 2001/02/04 15:32:23 stevesk Exp $");
28 #include <openssl/crypto.h>
29 #include <openssl/bio.h>
30 #include <openssl/bn.h>
31 #include <openssl/dh.h>
32 #include <openssl/pem.h>
45 #define KEX_COOKIE_LEN 16
48 kex_init(char *myproposal[PROPOSAL_MAX])
50 int first_kex_packet_follows = 0;
51 u_char cookie[KEX_COOKIE_LEN];
54 Buffer *ki = xmalloc(sizeof(*ki));
55 for (i = 0; i < KEX_COOKIE_LEN; i++) {
58 cookie[i] = rand & 0xff;
62 buffer_append(ki, (char *)cookie, sizeof cookie);
63 for (i = 0; i < PROPOSAL_MAX; i++)
64 buffer_put_cstring(ki, myproposal[i]);
65 buffer_put_char(ki, first_kex_packet_follows);
66 buffer_put_int(ki, 0); /* uint32 reserved */
70 /* send kexinit, parse and save reply */
73 Buffer *my_kexinit, Buffer *peer_kexint,
74 char *peer_proposal[PROPOSAL_MAX])
80 debug("send KEXINIT");
81 packet_start(SSH2_MSG_KEXINIT);
82 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
88 * read and save raw KEXINIT payload in buffer. this is used during
89 * computation of the session_id and the session keys.
91 debug("wait KEXINIT");
92 packet_read_expect(&plen, SSH2_MSG_KEXINIT);
93 ptr = packet_get_raw(&plen);
94 buffer_append(peer_kexint, ptr, plen);
96 /* parse packet and save algorithm proposal */
98 for (i = 0; i < KEX_COOKIE_LEN; i++)
100 /* extract kex init proposal strings */
101 for (i = 0; i < PROPOSAL_MAX; i++) {
102 peer_proposal[i] = packet_get_string(NULL);
103 debug("got kexinit: %s", peer_proposal[i]);
105 /* first kex follow / reserved */
106 i = packet_get_char();
107 debug("first kex follow: %d ", i);
108 i = packet_get_int();
109 debug("reserved: %d ", i);
114 /* diffie-hellman-group1-sha1 */
117 dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
120 int n = BN_num_bits(dh_pub);
124 log("invalid public DH value: negativ");
127 for (i = 0; i <= n; i++)
128 if (BN_is_bit_set(dh_pub, i))
130 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
132 /* if g==2 and bits_set==1 then computing log_g(dh_pub) is trivial */
133 if (bits_set > 1 && (BN_cmp(dh_pub, dh->p) == -1))
135 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
145 if (DH_generate_key(dh) == 0)
146 fatal("DH_generate_key");
148 fatal("dh_new_group1: too many bad keys: giving up");
149 } while (!dh_pub_is_valid(dh, dh->pub_key));
153 dh_new_group_asc(const char *gen, const char *modulus)
162 if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
163 fatal("BN_hex2bn p");
164 if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
165 fatal("BN_hex2bn g");
171 * This just returns the group, we still need to generate the exchange
176 dh_new_group(BIGNUM *gen, BIGNUM *modulus)
192 static char *gen = "2", *group1 =
193 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
194 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
195 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
196 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
197 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
198 "FFFFFFFF" "FFFFFFFF";
200 return (dh_new_group_asc(gen, group1));
204 dump_digest(u_char *digest, int len)
207 for (i = 0; i< len; i++){
208 fprintf(stderr, "%02x", digest[i]);
210 fprintf(stderr, " ");
212 fprintf(stderr, "\n");
217 char *client_version_string,
218 char *server_version_string,
219 char *ckexinit, int ckexinitlen,
220 char *skexinit, int skexinitlen,
221 char *serverhostkeyblob, int sbloblen,
222 BIGNUM *client_dh_pub,
223 BIGNUM *server_dh_pub,
224 BIGNUM *shared_secret)
227 static u_char digest[EVP_MAX_MD_SIZE];
228 EVP_MD *evp_md = EVP_sha1();
232 buffer_put_string(&b, client_version_string, strlen(client_version_string));
233 buffer_put_string(&b, server_version_string, strlen(server_version_string));
235 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
236 buffer_put_int(&b, ckexinitlen+1);
237 buffer_put_char(&b, SSH2_MSG_KEXINIT);
238 buffer_append(&b, ckexinit, ckexinitlen);
239 buffer_put_int(&b, skexinitlen+1);
240 buffer_put_char(&b, SSH2_MSG_KEXINIT);
241 buffer_append(&b, skexinit, skexinitlen);
243 buffer_put_string(&b, serverhostkeyblob, sbloblen);
244 buffer_put_bignum2(&b, client_dh_pub);
245 buffer_put_bignum2(&b, server_dh_pub);
246 buffer_put_bignum2(&b, shared_secret);
252 EVP_DigestInit(&md, evp_md);
253 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
254 EVP_DigestFinal(&md, digest, NULL);
259 dump_digest(digest, evp_md->md_size);
266 char *client_version_string,
267 char *server_version_string,
268 char *ckexinit, int ckexinitlen,
269 char *skexinit, int skexinitlen,
270 char *serverhostkeyblob, int sbloblen,
271 int minbits, BIGNUM *prime, BIGNUM *gen,
272 BIGNUM *client_dh_pub,
273 BIGNUM *server_dh_pub,
274 BIGNUM *shared_secret)
277 static u_char digest[EVP_MAX_MD_SIZE];
278 EVP_MD *evp_md = EVP_sha1();
282 buffer_put_string(&b, client_version_string, strlen(client_version_string));
283 buffer_put_string(&b, server_version_string, strlen(server_version_string));
285 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
286 buffer_put_int(&b, ckexinitlen+1);
287 buffer_put_char(&b, SSH2_MSG_KEXINIT);
288 buffer_append(&b, ckexinit, ckexinitlen);
289 buffer_put_int(&b, skexinitlen+1);
290 buffer_put_char(&b, SSH2_MSG_KEXINIT);
291 buffer_append(&b, skexinit, skexinitlen);
293 buffer_put_string(&b, serverhostkeyblob, sbloblen);
294 buffer_put_int(&b, minbits);
295 buffer_put_bignum2(&b, prime);
296 buffer_put_bignum2(&b, gen);
297 buffer_put_bignum2(&b, client_dh_pub);
298 buffer_put_bignum2(&b, server_dh_pub);
299 buffer_put_bignum2(&b, shared_secret);
305 EVP_DigestInit(&md, evp_md);
306 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
307 EVP_DigestFinal(&md, digest, NULL);
312 dump_digest(digest, evp_md->md_size);
318 derive_key(int id, int need, u_char *hash, BIGNUM *shared_secret)
321 EVP_MD *evp_md = EVP_sha1();
325 int mdsz = evp_md->md_size;
326 u_char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
329 buffer_put_bignum2(&b, shared_secret);
331 EVP_DigestInit(&md, evp_md);
332 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
333 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
334 EVP_DigestUpdate(&md, &c, 1); /* key id */
335 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
336 EVP_DigestFinal(&md, digest, NULL);
339 for (have = mdsz; need > have; have += mdsz) {
340 EVP_DigestInit(&md, evp_md);
341 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
342 EVP_DigestUpdate(&md, hash, mdsz);
343 EVP_DigestUpdate(&md, digest, have);
344 EVP_DigestFinal(&md, digest + have, NULL);
348 fprintf(stderr, "Digest '%c'== ", c);
349 dump_digest(digest, need);
360 get_match(char *client, char *server)
362 char *sproposals[MAX_PROP];
363 char *c, *s, *p, *ret, *cp, *sp;
364 int i, j, nproposals;
366 c = cp = xstrdup(client);
367 s = sp = xstrdup(server);
369 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
370 (p = strsep(&sp, SEP)), i++) {
378 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
379 (p = strsep(&cp, SEP)), i++) {
380 for (j = 0; j < nproposals; j++) {
381 if (strcmp(p, sproposals[j]) == 0) {
394 choose_enc(Enc *enc, char *client, char *server)
396 char *name = get_match(client, server);
398 fatal("no matching cipher found: client %s server %s", client, server);
399 enc->cipher = cipher_by_name(name);
400 if (enc->cipher == NULL)
401 fatal("matching cipher is not supported: %s", name);
408 choose_mac(Mac *mac, char *client, char *server)
410 char *name = get_match(client, server);
412 fatal("no matching mac found: client %s server %s", client, server);
413 if (strcmp(name, "hmac-md5") == 0) {
415 } else if (strcmp(name, "hmac-sha1") == 0) {
416 mac->md = EVP_sha1();
417 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
418 mac->md = EVP_ripemd160();
420 fatal("unsupported mac %s", name);
423 mac->mac_len = mac->md->md_size;
424 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
429 choose_comp(Comp *comp, char *client, char *server)
431 char *name = get_match(client, server);
433 fatal("no matching comp found: client %s server %s", client, server);
434 if (strcmp(name, "zlib") == 0) {
436 } else if (strcmp(name, "none") == 0) {
439 fatal("unsupported comp %s", name);
444 choose_kex(Kex *k, char *client, char *server)
446 k->name = get_match(client, server);
449 if (strcmp(k->name, KEX_DH1) == 0) {
450 k->kex_type = DH_GRP1_SHA1;
451 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
452 k->kex_type = DH_GEX_SHA1;
454 fatal("bad kex alg %s", k->name);
457 choose_hostkeyalg(Kex *k, char *client, char *server)
459 char *hostkeyalg = get_match(client, server);
460 if (hostkeyalg == NULL)
461 fatal("no hostkey alg");
462 k->hostkey_type = key_type_from_name(hostkeyalg);
463 if (k->hostkey_type == KEY_UNSPEC)
464 fatal("bad hostkey alg '%s'", hostkeyalg);
469 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
472 int ctos; /* direction: if true client-to-server */
476 k = xmalloc(sizeof(*k));
477 memset(k, 0, sizeof(*k));
480 for (mode = 0; mode < MODE_MAX; mode++) {
481 int nenc, nmac, ncomp;
482 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
483 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
484 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
485 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
486 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
487 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
488 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
489 debug("kex: %s %s %s %s",
490 ctos ? "client->server" : "server->client",
495 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
496 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
497 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
499 for (mode = 0; mode < MODE_MAX; mode++) {
500 if (need < k->enc[mode].cipher->key_len)
501 need = k->enc[mode].cipher->key_len;
502 if (need < k->enc[mode].cipher->block_size)
503 need = k->enc[mode].cipher->block_size;
504 if (need < k->mac[mode].key_len)
505 need = k->mac[mode].key_len;
507 /* XXX need runden? */
513 kex_derive_keys(Kex *k, u_char *hash, BIGNUM *shared_secret)
520 for (i = 0; i < NKEYS; i++)
521 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
523 for (mode = 0; mode < MODE_MAX; mode++) {
524 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
525 k->enc[mode].iv = keys[ctos ? 0 : 1];
526 k->enc[mode].key = keys[ctos ? 2 : 3];
527 k->mac[mode].key = keys[ctos ? 4 : 5];