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.
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.
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.
31 RCSID("$OpenBSD: kex.c,v 1.9 2000/07/10 16:30:25 ho Exp $");
42 #include <openssl/bn.h>
43 #include <openssl/dh.h>
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>
53 #define KEX_COOKIE_LEN 16
56 kex_init(char *myproposal[PROPOSAL_MAX])
58 int first_kex_packet_follows = 0;
59 unsigned char cookie[KEX_COOKIE_LEN];
62 Buffer *ki = xmalloc(sizeof(*ki));
63 for (i = 0; i < KEX_COOKIE_LEN; i++) {
66 cookie[i] = rand & 0xff;
70 buffer_append(ki, (char *)cookie, sizeof cookie);
71 for (i = 0; i < PROPOSAL_MAX; i++)
72 buffer_put_cstring(ki, myproposal[i]);
73 buffer_put_char(ki, first_kex_packet_follows);
74 buffer_put_int(ki, 0); /* uint32 reserved */
78 /* send kexinit, parse and save reply */
81 Buffer *my_kexinit, Buffer *peer_kexint,
82 char *peer_proposal[PROPOSAL_MAX])
88 debug("send KEXINIT");
89 packet_start(SSH2_MSG_KEXINIT);
90 packet_put_raw(buffer_ptr(my_kexinit), buffer_len(my_kexinit));
96 * read and save raw KEXINIT payload in buffer. this is used during
97 * computation of the session_id and the session keys.
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);
104 /* parse packet and save algorithm proposal */
106 for (i = 0; i < KEX_COOKIE_LEN; i++)
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]);
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);
122 /* diffie-hellman-group1-sha1 */
125 dh_pub_is_valid(DH *dh, BIGNUM *dh_pub)
128 int n = BN_num_bits(dh_pub);
131 /* we only accept g==2 */
132 if (!BN_is_word(dh->g, 2)) {
133 log("invalid DH base != 2");
137 log("invalid public DH value: negativ");
140 for (i = 0; i <= n; i++)
141 if (BN_is_bit_set(dh_pub, i))
143 debug("bits set: %d/%d", bits_set, BN_num_bits(dh->p));
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))
148 log("invalid public DH value (%d/%d)", bits_set, BN_num_bits(dh->p));
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";
167 ret = BN_hex2bn(&dh->p, group1);
173 BN_set_word(dh->g, 2);
175 if (DH_generate_key(dh) == 0)
176 fatal("DH_generate_key");
178 fatal("dh_new_group1: too many bad keys: giving up");
179 } while (!dh_pub_is_valid(dh, dh->pub_key));
184 dump_digest(unsigned char *digest, int len)
187 for (i = 0; i< len; i++){
188 fprintf(stderr, "%02x", digest[i]);
190 fprintf(stderr, " ");
192 fprintf(stderr, "\n");
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)
207 static unsigned char digest[EVP_MAX_MD_SIZE];
208 EVP_MD *evp_md = EVP_sha1();
212 buffer_put_string(&b, client_version_string, strlen(client_version_string));
213 buffer_put_string(&b, server_version_string, strlen(server_version_string));
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);
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);
232 EVP_DigestInit(&md, evp_md);
233 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
234 EVP_DigestFinal(&md, digest, NULL);
239 dump_digest(digest, evp_md->md_size);
245 derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
248 EVP_MD *evp_md = EVP_sha1();
252 int mdsz = evp_md->md_size;
253 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
256 buffer_put_bignum2(&b, shared_secret);
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);
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);
275 fprintf(stderr, "Digest '%c'== ", c);
276 dump_digest(digest, need);
287 get_match(char *client, char *server)
289 char *sproposals[MAX_PROP];
290 char *c, *s, *p, *ret, *cp, *sp;
291 int i, j, nproposals;
293 c = cp = xstrdup(client);
294 s = sp = xstrdup(server);
296 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
297 (p = strsep(&sp, SEP)), i++) {
305 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
306 (p = strsep(&cp, SEP)), i++) {
307 for (j = 0; j < nproposals; j++) {
308 if (strcmp(p, sproposals[j]) == 0) {
321 choose_enc(Enc *enc, char *client, char *server)
323 char *name = get_match(client, server);
325 fatal("no matching cipher found: client %s server %s", client, server);
326 enc->type = cipher_number(name);
329 case SSH_CIPHER_3DES_CBC:
334 case SSH_CIPHER_BLOWFISH_CBC:
335 case SSH_CIPHER_CAST128_CBC:
340 case SSH_CIPHER_ARCFOUR:
346 fatal("unsupported cipher %s", name);
354 choose_mac(Mac *mac, char *client, char *server)
356 char *name = get_match(client, server);
358 fatal("no matching mac found: client %s server %s", client, server);
359 if (strcmp(name, "hmac-md5") == 0) {
361 } else if (strcmp(name, "hmac-sha1") == 0) {
362 mac->md = EVP_sha1();
363 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
364 mac->md = EVP_ripemd160();
366 fatal("unsupported mac %s", name);
369 mac->mac_len = mac->md->md_size;
370 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
375 choose_comp(Comp *comp, char *client, char *server)
377 char *name = get_match(client, server);
379 fatal("no matching comp found: client %s server %s", client, server);
380 if (strcmp(name, "zlib") == 0) {
382 } else if (strcmp(name, "none") == 0) {
385 fatal("unsupported comp %s", name);
390 choose_kex(Kex *k, char *client, char *server)
392 k->name = get_match(client, server);
395 if (strcmp(k->name, KEX_DH1) != 0)
396 fatal("bad kex alg %s", k->name);
399 choose_hostkeyalg(Kex *k, char *client, char *server)
401 k->hostkeyalg = get_match(client, server);
402 if (k->hostkeyalg == NULL)
403 fatal("no hostkey alg");
404 if (strcmp(k->hostkeyalg, KEX_DSS) != 0)
405 fatal("bad hostkey alg %s", k->hostkeyalg);
409 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
412 int ctos; /* direction: if true client-to-server */
416 k = xmalloc(sizeof(*k));
417 memset(k, 0, sizeof(*k));
420 for (mode = 0; mode < MODE_MAX; mode++) {
421 int nenc, nmac, ncomp;
422 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
423 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
424 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
425 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
426 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
427 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
428 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
429 debug("kex: %s %s %s %s",
430 ctos ? "client->server" : "server->client",
435 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
436 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
437 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
439 for (mode = 0; mode < MODE_MAX; mode++) {
440 if (need < k->enc[mode].key_len)
441 need = k->enc[mode].key_len;
442 if (need < k->enc[mode].iv_len)
443 need = k->enc[mode].iv_len;
444 if (need < k->mac[mode].key_len)
445 need = k->mac[mode].key_len;
447 /* XXX need runden? */
453 kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
458 unsigned char *keys[NKEYS];
460 for (i = 0; i < NKEYS; i++)
461 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
463 for (mode = 0; mode < MODE_MAX; mode++) {
464 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
465 k->enc[mode].iv = keys[ctos ? 0 : 1];
466 k->enc[mode].key = keys[ctos ? 2 : 3];
467 k->mac[mode].key = keys[ctos ? 4 : 5];