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.13 2000/11/12 19:50:37 markus 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));
157 dh_new_group_asc(const char *gen, const char *modulus)
166 if ((ret = BN_hex2bn(&dh->p, modulus)) < 0)
167 fatal("BN_hex2bn p");
168 if ((ret = BN_hex2bn(&dh->g, gen)) < 0)
169 fatal("BN_hex2bn g");
171 return (dh_gen_key(dh));
175 dh_new_group(BIGNUM *gen, BIGNUM *modulus)
185 return (dh_gen_key(dh));
191 static char *gen = "2", *group1 =
192 "FFFFFFFF" "FFFFFFFF" "C90FDAA2" "2168C234" "C4C6628B" "80DC1CD1"
193 "29024E08" "8A67CC74" "020BBEA6" "3B139B22" "514A0879" "8E3404DD"
194 "EF9519B3" "CD3A431B" "302B0A6D" "F25F1437" "4FE1356D" "6D51C245"
195 "E485B576" "625E7EC6" "F44C42E9" "A637ED6B" "0BFF5CB6" "F406B7ED"
196 "EE386BFB" "5A899FA5" "AE9F2411" "7C4B1FE6" "49286651" "ECE65381"
197 "FFFFFFFF" "FFFFFFFF";
199 return (dh_new_group_asc(gen, group1));
203 dump_digest(unsigned char *digest, int len)
206 for (i = 0; i< len; i++){
207 fprintf(stderr, "%02x", digest[i]);
209 fprintf(stderr, " ");
211 fprintf(stderr, "\n");
216 char *client_version_string,
217 char *server_version_string,
218 char *ckexinit, int ckexinitlen,
219 char *skexinit, int skexinitlen,
220 char *serverhostkeyblob, int sbloblen,
221 BIGNUM *client_dh_pub,
222 BIGNUM *server_dh_pub,
223 BIGNUM *shared_secret)
226 static unsigned char digest[EVP_MAX_MD_SIZE];
227 EVP_MD *evp_md = EVP_sha1();
231 buffer_put_string(&b, client_version_string, strlen(client_version_string));
232 buffer_put_string(&b, server_version_string, strlen(server_version_string));
234 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
235 buffer_put_int(&b, ckexinitlen+1);
236 buffer_put_char(&b, SSH2_MSG_KEXINIT);
237 buffer_append(&b, ckexinit, ckexinitlen);
238 buffer_put_int(&b, skexinitlen+1);
239 buffer_put_char(&b, SSH2_MSG_KEXINIT);
240 buffer_append(&b, skexinit, skexinitlen);
242 buffer_put_string(&b, serverhostkeyblob, sbloblen);
243 buffer_put_bignum2(&b, client_dh_pub);
244 buffer_put_bignum2(&b, server_dh_pub);
245 buffer_put_bignum2(&b, shared_secret);
251 EVP_DigestInit(&md, evp_md);
252 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
253 EVP_DigestFinal(&md, digest, NULL);
258 dump_digest(digest, evp_md->md_size);
265 char *client_version_string,
266 char *server_version_string,
267 char *ckexinit, int ckexinitlen,
268 char *skexinit, int skexinitlen,
269 char *serverhostkeyblob, int sbloblen,
270 int minbits, BIGNUM *prime, BIGNUM *gen,
271 BIGNUM *client_dh_pub,
272 BIGNUM *server_dh_pub,
273 BIGNUM *shared_secret)
276 static unsigned char digest[EVP_MAX_MD_SIZE];
277 EVP_MD *evp_md = EVP_sha1();
281 buffer_put_string(&b, client_version_string, strlen(client_version_string));
282 buffer_put_string(&b, server_version_string, strlen(server_version_string));
284 /* kexinit messages: fake header: len+SSH2_MSG_KEXINIT */
285 buffer_put_int(&b, ckexinitlen+1);
286 buffer_put_char(&b, SSH2_MSG_KEXINIT);
287 buffer_append(&b, ckexinit, ckexinitlen);
288 buffer_put_int(&b, skexinitlen+1);
289 buffer_put_char(&b, SSH2_MSG_KEXINIT);
290 buffer_append(&b, skexinit, skexinitlen);
292 buffer_put_string(&b, serverhostkeyblob, sbloblen);
293 buffer_put_int(&b, minbits);
294 buffer_put_bignum2(&b, prime);
295 buffer_put_bignum2(&b, gen);
296 buffer_put_bignum2(&b, client_dh_pub);
297 buffer_put_bignum2(&b, server_dh_pub);
298 buffer_put_bignum2(&b, shared_secret);
304 EVP_DigestInit(&md, evp_md);
305 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
306 EVP_DigestFinal(&md, digest, NULL);
311 dump_digest(digest, evp_md->md_size);
317 derive_key(int id, int need, char unsigned *hash, BIGNUM *shared_secret)
320 EVP_MD *evp_md = EVP_sha1();
324 int mdsz = evp_md->md_size;
325 unsigned char *digest = xmalloc(((need+mdsz-1)/mdsz)*mdsz);
328 buffer_put_bignum2(&b, shared_secret);
330 EVP_DigestInit(&md, evp_md);
331 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b)); /* shared_secret K */
332 EVP_DigestUpdate(&md, hash, mdsz); /* transport-06 */
333 EVP_DigestUpdate(&md, &c, 1); /* key id */
334 EVP_DigestUpdate(&md, hash, mdsz); /* session id */
335 EVP_DigestFinal(&md, digest, NULL);
338 for (have = mdsz; need > have; have += mdsz) {
339 EVP_DigestInit(&md, evp_md);
340 EVP_DigestUpdate(&md, buffer_ptr(&b), buffer_len(&b));
341 EVP_DigestUpdate(&md, hash, mdsz);
342 EVP_DigestUpdate(&md, digest, have);
343 EVP_DigestFinal(&md, digest + have, NULL);
347 fprintf(stderr, "Digest '%c'== ", c);
348 dump_digest(digest, need);
359 get_match(char *client, char *server)
361 char *sproposals[MAX_PROP];
362 char *c, *s, *p, *ret, *cp, *sp;
363 int i, j, nproposals;
365 c = cp = xstrdup(client);
366 s = sp = xstrdup(server);
368 for ((p = strsep(&sp, SEP)), i=0; p && *p != '\0';
369 (p = strsep(&sp, SEP)), i++) {
377 for ((p = strsep(&cp, SEP)), i=0; p && *p != '\0';
378 (p = strsep(&cp, SEP)), i++) {
379 for (j = 0; j < nproposals; j++) {
380 if (strcmp(p, sproposals[j]) == 0) {
393 choose_enc(Enc *enc, char *client, char *server)
395 char *name = get_match(client, server);
397 fatal("no matching cipher found: client %s server %s", client, server);
398 enc->cipher = cipher_by_name(name);
399 if (enc->cipher == NULL)
400 fatal("matching cipher is not supported: %s", name);
407 choose_mac(Mac *mac, char *client, char *server)
409 char *name = get_match(client, server);
411 fatal("no matching mac found: client %s server %s", client, server);
412 if (strcmp(name, "hmac-md5") == 0) {
414 } else if (strcmp(name, "hmac-sha1") == 0) {
415 mac->md = EVP_sha1();
416 } else if (strcmp(name, "hmac-ripemd160@openssh.com") == 0) {
417 mac->md = EVP_ripemd160();
419 fatal("unsupported mac %s", name);
422 mac->mac_len = mac->md->md_size;
423 mac->key_len = (datafellows & SSH_BUG_HMAC) ? 16 : mac->mac_len;
428 choose_comp(Comp *comp, char *client, char *server)
430 char *name = get_match(client, server);
432 fatal("no matching comp found: client %s server %s", client, server);
433 if (strcmp(name, "zlib") == 0) {
435 } else if (strcmp(name, "none") == 0) {
438 fatal("unsupported comp %s", name);
443 choose_kex(Kex *k, char *client, char *server)
445 k->name = get_match(client, server);
448 if (strcmp(k->name, KEX_DH1) == 0) {
449 k->kex_type = DH_GRP1_SHA1;
450 } else if (strcmp(k->name, KEX_DHGEX) == 0) {
451 k->kex_type = DH_GEX_SHA1;
453 fatal("bad kex alg %s", k->name);
456 choose_hostkeyalg(Kex *k, char *client, char *server)
458 char *hostkeyalg = get_match(client, server);
459 if (hostkeyalg == NULL)
460 fatal("no hostkey alg");
461 k->hostkey_type = key_type_from_name(hostkeyalg);
462 if (k->hostkey_type == KEY_UNSPEC)
463 fatal("bad hostkey alg '%s'", hostkeyalg);
467 kex_choose_conf(char *cprop[PROPOSAL_MAX], char *sprop[PROPOSAL_MAX], int server)
470 int ctos; /* direction: if true client-to-server */
474 k = xmalloc(sizeof(*k));
475 memset(k, 0, sizeof(*k));
478 for (mode = 0; mode < MODE_MAX; mode++) {
479 int nenc, nmac, ncomp;
480 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
481 nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
482 nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
483 ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
484 choose_enc (&k->enc [mode], cprop[nenc], sprop[nenc]);
485 choose_mac (&k->mac [mode], cprop[nmac], sprop[nmac]);
486 choose_comp(&k->comp[mode], cprop[ncomp], sprop[ncomp]);
487 debug("kex: %s %s %s %s",
488 ctos ? "client->server" : "server->client",
493 choose_kex(k, cprop[PROPOSAL_KEX_ALGS], sprop[PROPOSAL_KEX_ALGS]);
494 choose_hostkeyalg(k, cprop[PROPOSAL_SERVER_HOST_KEY_ALGS],
495 sprop[PROPOSAL_SERVER_HOST_KEY_ALGS]);
497 for (mode = 0; mode < MODE_MAX; mode++) {
498 if (need < k->enc[mode].cipher->key_len)
499 need = k->enc[mode].cipher->key_len;
500 if (need < k->enc[mode].cipher->block_size)
501 need = k->enc[mode].cipher->block_size;
502 if (need < k->mac[mode].key_len)
503 need = k->mac[mode].key_len;
505 /* XXX need runden? */
511 kex_derive_keys(Kex *k, unsigned char *hash, BIGNUM *shared_secret)
516 unsigned char *keys[NKEYS];
518 for (i = 0; i < NKEYS; i++)
519 keys[i] = derive_key('A'+i, k->we_need, hash, shared_secret);
521 for (mode = 0; mode < MODE_MAX; mode++) {
522 ctos = (!k->server && mode == MODE_OUT) || (k->server && mode == MODE_IN);
523 k->enc[mode].iv = keys[ctos ? 0 : 1];
524 k->enc[mode].key = keys[ctos ? 2 : 3];
525 k->mac[mode].key = keys[ctos ? 4 : 5];