xref: /plan9-contrib/sys/src/cmd/ssh2/dh.c (revision c59d18e224d2a4b044d6b8f2a0ff453a56c17312)
163afb9a5SDavid du Colombier #include <u.h>
263afb9a5SDavid du Colombier #include <libc.h>
363afb9a5SDavid du Colombier #include <mp.h>
463afb9a5SDavid du Colombier #include <libsec.h>
563afb9a5SDavid du Colombier #include <fcall.h>
663afb9a5SDavid du Colombier #include <thread.h>
763afb9a5SDavid du Colombier #include <9p.h>
863afb9a5SDavid du Colombier #include <auth.h>
963afb9a5SDavid du Colombier #include <ip.h>
1063afb9a5SDavid du Colombier #include <pool.h>
1163afb9a5SDavid du Colombier #include "netssh.h"
1263afb9a5SDavid du Colombier 
13998526ebSDavid du Colombier #undef VERIFYKEYS		/* TODO until it's fixed */
14998526ebSDavid du Colombier 
15998526ebSDavid du Colombier enum {
16998526ebSDavid du Colombier 	Errnokey = -2,	/* no key on keyring */
17998526ebSDavid du Colombier 	Errnoverify,	/* factotum found a key, but verification failed */
18998526ebSDavid du Colombier 	Errfactotum,	/* factotum failure (e.g., no key) */
19998526ebSDavid du Colombier 	Errnone,	/* key verified */
20998526ebSDavid du Colombier };
21998526ebSDavid du Colombier 
2263afb9a5SDavid du Colombier static int dh_server(Conn *, Packet *, mpint *, int);
23*c59d18e2SDavid du Colombier static int dh_client1(Conn *, mpint *, int, int);
24*c59d18e2SDavid du Colombier static int dh_client2(Conn *, Packet *, mpint *, int);
2563afb9a5SDavid du Colombier static void genkeys(Conn *, uchar [], mpint *);
2663afb9a5SDavid du Colombier 
2763afb9a5SDavid du Colombier /*
2863afb9a5SDavid du Colombier  * Second Oakley Group from RFC 2409
2963afb9a5SDavid du Colombier  */
3063afb9a5SDavid du Colombier static char *group1p =
3163afb9a5SDavid du Colombier          "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
3263afb9a5SDavid du Colombier          "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
3363afb9a5SDavid du Colombier          "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
3463afb9a5SDavid du Colombier          "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
3563afb9a5SDavid du Colombier          "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
3663afb9a5SDavid du Colombier          "FFFFFFFFFFFFFFFF";
3763afb9a5SDavid du Colombier 
3863afb9a5SDavid du Colombier /*
3963afb9a5SDavid du Colombier  * 2048-bit MODP group (id 14) from RFC 3526
4063afb9a5SDavid du Colombier */
4163afb9a5SDavid du Colombier static char *group14p =
4263afb9a5SDavid du Colombier       "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
4363afb9a5SDavid du Colombier       "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
4463afb9a5SDavid du Colombier       "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
4563afb9a5SDavid du Colombier       "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
4663afb9a5SDavid du Colombier       "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
4763afb9a5SDavid du Colombier       "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
4863afb9a5SDavid du Colombier       "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
4963afb9a5SDavid du Colombier       "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
5063afb9a5SDavid du Colombier       "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
5163afb9a5SDavid du Colombier       "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
5263afb9a5SDavid du Colombier       "15728E5A8AACAA68FFFFFFFFFFFFFFFF";
5363afb9a5SDavid du Colombier 
5463afb9a5SDavid du Colombier mpint *two, *p1, *p14;
5563afb9a5SDavid du Colombier int nokeyverify;
5663afb9a5SDavid du Colombier 
5763afb9a5SDavid du Colombier static DSApriv mydsskey;
5863afb9a5SDavid du Colombier static RSApriv myrsakey;
5963afb9a5SDavid du Colombier 
6063afb9a5SDavid du Colombier void
dh_init(PKA * pkas[])6163afb9a5SDavid du Colombier dh_init(PKA *pkas[])
6263afb9a5SDavid du Colombier {
6363afb9a5SDavid du Colombier 	char *buf, *p, *st, *end;
6463afb9a5SDavid du Colombier 	int fd, n, k;
6563afb9a5SDavid du Colombier 
6663afb9a5SDavid du Colombier 	if(debug > 1)
6763afb9a5SDavid du Colombier 		sshdebug(nil, "dh_init");
6863afb9a5SDavid du Colombier 	k = 0;
6963afb9a5SDavid du Colombier 	pkas[k] = nil;
7063afb9a5SDavid du Colombier 	fmtinstall('M', mpfmt);
7163afb9a5SDavid du Colombier 	two = strtomp("2", nil, 10, nil);
7263afb9a5SDavid du Colombier 	p1 = strtomp(group1p, nil, 16, nil);
7363afb9a5SDavid du Colombier 	p14 = strtomp(group14p, nil, 16, nil);
7463afb9a5SDavid du Colombier 
7563afb9a5SDavid du Colombier 	/*
7663afb9a5SDavid du Colombier 	 * this really should be done through factotum
7763afb9a5SDavid du Colombier 	 */
7863afb9a5SDavid du Colombier 	p = getenv("rsakey");
7963afb9a5SDavid du Colombier 	if (p != nil) {
8063afb9a5SDavid du Colombier 		remove("/env/rsakey");
8163afb9a5SDavid du Colombier 		st = buf = p;
8263afb9a5SDavid du Colombier 		end = buf + strlen(p);
8363afb9a5SDavid du Colombier 	} else {
8463afb9a5SDavid du Colombier 		/*
8563afb9a5SDavid du Colombier 		 * it would be better to use bio and rdline here instead of
8663afb9a5SDavid du Colombier 		 * reading all of factotum's contents into memory at once.
8763afb9a5SDavid du Colombier 		 */
8863afb9a5SDavid du Colombier 		buf = emalloc9p(Maxfactotum);
8963afb9a5SDavid du Colombier 		fd = open("rsakey", OREAD);
9063afb9a5SDavid du Colombier 		if (fd < 0 && (fd = open("/mnt/factotum/ctl", OREAD)) < 0)
9163afb9a5SDavid du Colombier 			goto norsa;
9263afb9a5SDavid du Colombier 		n = readn(fd, buf, Maxfactotum - 1);
9363afb9a5SDavid du Colombier 		buf[n >= 0? n: 0] = 0;
9463afb9a5SDavid du Colombier 		close(fd);
9563afb9a5SDavid du Colombier 		assert(n < Maxfactotum - 1);
9663afb9a5SDavid du Colombier 
9763afb9a5SDavid du Colombier 		st = strstr(buf, "proto=rsa");
9863afb9a5SDavid du Colombier 		if (st == nil) {
9963afb9a5SDavid du Colombier 			sshlog(nil, "no proto=rsa key in factotum");
10063afb9a5SDavid du Colombier 			goto norsa;
10163afb9a5SDavid du Colombier 		}
10263afb9a5SDavid du Colombier 		end = st;
10363afb9a5SDavid du Colombier 		for (; st > buf && *st != '\n'; --st)
10463afb9a5SDavid du Colombier 			;
10563afb9a5SDavid du Colombier 		for (; end < buf + Maxfactotum && *end != '\n'; ++end)
10663afb9a5SDavid du Colombier 			;
10763afb9a5SDavid du Colombier 	}
10863afb9a5SDavid du Colombier 	p = strstr(st, " n=");
10963afb9a5SDavid du Colombier 	if (p == nil || p > end) {
11063afb9a5SDavid du Colombier 		sshlog(nil, "no key (n) found");
11163afb9a5SDavid du Colombier 		free(buf);
11263afb9a5SDavid du Colombier 		return;
11363afb9a5SDavid du Colombier 	}
11463afb9a5SDavid du Colombier 	myrsakey.pub.n = strtomp(p+3, nil, 16, nil);
11563afb9a5SDavid du Colombier 	if (debug > 1)
11663afb9a5SDavid du Colombier 		sshdebug(nil, "n=%M", myrsakey.pub.n);
11763afb9a5SDavid du Colombier 	p = strstr(st, " ek=");
11863afb9a5SDavid du Colombier 	if (p == nil || p > end) {
11963afb9a5SDavid du Colombier 		sshlog(nil, "no key (ek) found");
12063afb9a5SDavid du Colombier 		free(buf);
12163afb9a5SDavid du Colombier 		return;
12263afb9a5SDavid du Colombier 	}
12363afb9a5SDavid du Colombier 	pkas[k++] = &rsa_pka;
12463afb9a5SDavid du Colombier 	pkas[k] = nil;
12563afb9a5SDavid du Colombier 	myrsakey.pub.ek = strtomp(p+4, nil, 16, nil);
12663afb9a5SDavid du Colombier 	if (debug > 1)
12763afb9a5SDavid du Colombier 		sshdebug(nil, "ek=%M", myrsakey.pub.ek);
12863afb9a5SDavid du Colombier 	p = strstr(st, " !dk=");
12963afb9a5SDavid du Colombier 	if (p == nil) {
13063afb9a5SDavid du Colombier 		p = strstr(st, "!dk?");
13163afb9a5SDavid du Colombier 		if (p == nil || p > end) {
13263afb9a5SDavid du Colombier 			// sshlog(nil, "no key (dk) found");
13363afb9a5SDavid du Colombier 			free(buf);
13463afb9a5SDavid du Colombier 			return;
13563afb9a5SDavid du Colombier 		}
13663afb9a5SDavid du Colombier 		goto norsa;
13763afb9a5SDavid du Colombier 	}
13863afb9a5SDavid du Colombier 	myrsakey.dk = strtomp(p+5, nil, 16, nil);
13963afb9a5SDavid du Colombier 	if (debug > 1)
14063afb9a5SDavid du Colombier 		sshdebug(nil, "dk=%M", myrsakey.dk);
14163afb9a5SDavid du Colombier norsa:
14263afb9a5SDavid du Colombier 	free(buf);
14363afb9a5SDavid du Colombier 
14463afb9a5SDavid du Colombier 	p = getenv("dsskey");
14563afb9a5SDavid du Colombier 	if (p != nil) {
14663afb9a5SDavid du Colombier 		remove("/env/dsskey");
14763afb9a5SDavid du Colombier 		buf = p;
14863afb9a5SDavid du Colombier 		end = buf + strlen(p);
14963afb9a5SDavid du Colombier 	} else {
15063afb9a5SDavid du Colombier 		/*
15163afb9a5SDavid du Colombier 		 * it would be better to use bio and rdline here instead of
15263afb9a5SDavid du Colombier 		 * reading all of factotum's contents into memory at once.
15363afb9a5SDavid du Colombier 		 */
15463afb9a5SDavid du Colombier 		buf = emalloc9p(Maxfactotum);
15563afb9a5SDavid du Colombier 		fd = open("dsskey", OREAD);
15663afb9a5SDavid du Colombier 		if (fd < 0 && (fd = open("/mnt/factotum/ctl", OREAD)) < 0)
15763afb9a5SDavid du Colombier 			return;
15863afb9a5SDavid du Colombier 		n = readn(fd, buf, Maxfactotum - 1);
15963afb9a5SDavid du Colombier 		buf[n >= 0? n: 0] = 0;
16063afb9a5SDavid du Colombier 		close(fd);
16163afb9a5SDavid du Colombier 		assert(n < Maxfactotum - 1);
16263afb9a5SDavid du Colombier 
16363afb9a5SDavid du Colombier 		st = strstr(buf, "proto=dsa");
16463afb9a5SDavid du Colombier 		if (st == nil) {
16563afb9a5SDavid du Colombier 			sshlog(nil, "no proto=dsa key in factotum");
16663afb9a5SDavid du Colombier 			free(buf);
16763afb9a5SDavid du Colombier 			return;
16863afb9a5SDavid du Colombier 		}
16963afb9a5SDavid du Colombier 		end = st;
17063afb9a5SDavid du Colombier 		for (; st > buf && *st != '\n'; --st)
17163afb9a5SDavid du Colombier 			;
17263afb9a5SDavid du Colombier 		for (; end < buf + Maxfactotum && *end != '\n'; ++end)
17363afb9a5SDavid du Colombier 			;
17463afb9a5SDavid du Colombier 	}
17563afb9a5SDavid du Colombier 	p = strstr(buf, " p=");
17663afb9a5SDavid du Colombier 	if (p == nil || p > end) {
17763afb9a5SDavid du Colombier 		sshlog(nil, "no key (p) found");
17863afb9a5SDavid du Colombier 		free(buf);
17963afb9a5SDavid du Colombier 		return;
18063afb9a5SDavid du Colombier 	}
18163afb9a5SDavid du Colombier 	mydsskey.pub.p = strtomp(p+3, nil, 16, nil);
18263afb9a5SDavid du Colombier 	p = strstr(buf, " q=");
18363afb9a5SDavid du Colombier 	if (p == nil || p > end) {
18463afb9a5SDavid du Colombier 		sshlog(nil, "no key (q) found");
18563afb9a5SDavid du Colombier 		free(buf);
18663afb9a5SDavid du Colombier 		return;
18763afb9a5SDavid du Colombier 	}
18863afb9a5SDavid du Colombier 	mydsskey.pub.q = strtomp(p+3, nil, 16, nil);
18963afb9a5SDavid du Colombier 	p = strstr(buf, " alpha=");
19063afb9a5SDavid du Colombier 	if (p == nil || p > end) {
19163afb9a5SDavid du Colombier 		sshlog(nil, "no key (g) found");
19263afb9a5SDavid du Colombier 		free(buf);
19363afb9a5SDavid du Colombier 		return;
19463afb9a5SDavid du Colombier 	}
19563afb9a5SDavid du Colombier 	mydsskey.pub.alpha = strtomp(p+7, nil, 16, nil);
19663afb9a5SDavid du Colombier 	p = strstr(buf, " key=");
19763afb9a5SDavid du Colombier 	if (p == nil || p > end) {
19863afb9a5SDavid du Colombier 		sshlog(nil, "no key (y) found");
19963afb9a5SDavid du Colombier 		free(buf);
20063afb9a5SDavid du Colombier 		return;
20163afb9a5SDavid du Colombier 	}
20263afb9a5SDavid du Colombier 	mydsskey.pub.key = strtomp(p+5, nil, 16, nil);
20363afb9a5SDavid du Colombier 	pkas[k++] = &dss_pka;
20463afb9a5SDavid du Colombier 	pkas[k] = nil;
20563afb9a5SDavid du Colombier 	p = strstr(buf, " !secret=");
20663afb9a5SDavid du Colombier 	if (p == nil) {
20763afb9a5SDavid du Colombier 		p = strstr(buf, "!secret?");
20863afb9a5SDavid du Colombier 		if (p == nil || p > end)
20963afb9a5SDavid du Colombier 			sshlog(nil, "no key (x) found");
21063afb9a5SDavid du Colombier 		free(buf);
21163afb9a5SDavid du Colombier 		return;
21263afb9a5SDavid du Colombier 	}
21363afb9a5SDavid du Colombier 	mydsskey.secret = strtomp(p+9, nil, 16, nil);
21463afb9a5SDavid du Colombier 	free(buf);
21563afb9a5SDavid du Colombier }
21663afb9a5SDavid du Colombier 
21763afb9a5SDavid du Colombier static Packet *
rsa_ks(Conn * c)21863afb9a5SDavid du Colombier rsa_ks(Conn *c)
21963afb9a5SDavid du Colombier {
22063afb9a5SDavid du Colombier 	Packet *ks;
22163afb9a5SDavid du Colombier 
22263afb9a5SDavid du Colombier 	if (myrsakey.pub.ek == nil || myrsakey.pub.n == nil) {
22363afb9a5SDavid du Colombier 		sshlog(c, "no public RSA key info");
22463afb9a5SDavid du Colombier 		return nil;
22563afb9a5SDavid du Colombier 	}
22663afb9a5SDavid du Colombier 	ks = new_packet(c);
22763afb9a5SDavid du Colombier 	add_string(ks, "ssh-rsa");
22863afb9a5SDavid du Colombier 	add_mp(ks, myrsakey.pub.ek);
22963afb9a5SDavid du Colombier 	add_mp(ks, myrsakey.pub.n);
23063afb9a5SDavid du Colombier 	return ks;
23163afb9a5SDavid du Colombier }
23263afb9a5SDavid du Colombier 
23363afb9a5SDavid du Colombier static void
esma_encode(uchar * h,uchar * em,int nb)23463afb9a5SDavid du Colombier esma_encode(uchar *h, uchar *em, int nb)
23563afb9a5SDavid du Colombier {
23663afb9a5SDavid du Colombier 	int n, i;
23763afb9a5SDavid du Colombier 	uchar hh[SHA1dlen];
23863afb9a5SDavid du Colombier 	static uchar sha1der[] = {
23963afb9a5SDavid du Colombier 		0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
24063afb9a5SDavid du Colombier 		0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
24163afb9a5SDavid du Colombier 	};
24263afb9a5SDavid du Colombier 
24363afb9a5SDavid du Colombier 	sha1(h, SHA1dlen, hh, nil);
24463afb9a5SDavid du Colombier 	n = nb - (nelem(sha1der) + SHA1dlen) - 3;
24563afb9a5SDavid du Colombier 	i = 0;
24663afb9a5SDavid du Colombier 	em[i++] = 0;
24763afb9a5SDavid du Colombier 	em[i++] = 1;
24863afb9a5SDavid du Colombier 	memset(em + i, 0xff, n);
24963afb9a5SDavid du Colombier 	i += n;
25063afb9a5SDavid du Colombier 	em[i++] = 0;
25163afb9a5SDavid du Colombier 	memmove(em + i, sha1der, sizeof sha1der);
25263afb9a5SDavid du Colombier 	i += sizeof sha1der;
25363afb9a5SDavid du Colombier 	memmove(em + i, hh, SHA1dlen);
25463afb9a5SDavid du Colombier }
25563afb9a5SDavid du Colombier 
25663afb9a5SDavid du Colombier static Packet *
rsa_sign(Conn * c,uchar * m,int nm)25763afb9a5SDavid du Colombier rsa_sign(Conn *c, uchar *m, int nm)
25863afb9a5SDavid du Colombier {
25963afb9a5SDavid du Colombier 	AuthRpc *ar;
26063afb9a5SDavid du Colombier 	Packet *sig;
26163afb9a5SDavid du Colombier 	mpint *s, *mm;
26263afb9a5SDavid du Colombier 	int fd, n, nbit;
26363afb9a5SDavid du Colombier 	uchar hh[SHA1dlen];
26463afb9a5SDavid du Colombier 	uchar *sstr, *em;
26563afb9a5SDavid du Colombier 
26663afb9a5SDavid du Colombier 	if (myrsakey.dk) {
26763afb9a5SDavid du Colombier 		nbit = mpsignif (myrsakey.pub.n);
26863afb9a5SDavid du Colombier 		n = (nbit + 7) / 8;
26963afb9a5SDavid du Colombier 		sstr = emalloc9p(n);
27063afb9a5SDavid du Colombier 		em = emalloc9p(n);
27163afb9a5SDavid du Colombier 		/* Compute s: RFC 3447 */
27263afb9a5SDavid du Colombier 		esma_encode(m, em, n);
27363afb9a5SDavid du Colombier 		mm = betomp(em, n, nil);
27463afb9a5SDavid du Colombier 		s = mpnew(nbit);
27563afb9a5SDavid du Colombier 		mpexp(mm, myrsakey.dk, myrsakey.pub.n, s);
27663afb9a5SDavid du Colombier 		mptobe(s, sstr, n, nil);
27763afb9a5SDavid du Colombier 		mpfree(mm);
27863afb9a5SDavid du Colombier 		mpfree(s);
27963afb9a5SDavid du Colombier 		free(em);
28063afb9a5SDavid du Colombier 	} else {
28163afb9a5SDavid du Colombier 		fd = open("/mnt/factotum/rpc", ORDWR);
28263afb9a5SDavid du Colombier 		if (fd < 0)
28363afb9a5SDavid du Colombier 			return nil;
28463afb9a5SDavid du Colombier 		sha1(m, nm, hh, nil);
28563afb9a5SDavid du Colombier 		ar = auth_allocrpc(fd);
28663afb9a5SDavid du Colombier 		if (ar == nil ||
28763afb9a5SDavid du Colombier 		    auth_rpc(ar, "start", "role=sign proto=rsa", 19) != ARok ||
28863afb9a5SDavid du Colombier 		    auth_rpc(ar, "write", hh, SHA1dlen) != ARok ||
28963afb9a5SDavid du Colombier 		    auth_rpc(ar, "read", nil, 0) != ARok ||
29063afb9a5SDavid du Colombier 		    ar->arg == nil) {
29163afb9a5SDavid du Colombier 			sshdebug(c, "got error in factotum: %r");
29263afb9a5SDavid du Colombier 			auth_freerpc(ar);
29363afb9a5SDavid du Colombier 			close(fd);
29463afb9a5SDavid du Colombier 			return nil;
29563afb9a5SDavid du Colombier 		}
29663afb9a5SDavid du Colombier 		sstr = emalloc9p(ar->narg);
29763afb9a5SDavid du Colombier 		memmove(sstr, ar->arg, ar->narg);
29863afb9a5SDavid du Colombier 		n = ar->narg;
29963afb9a5SDavid du Colombier 
30063afb9a5SDavid du Colombier 		auth_freerpc(ar);
30163afb9a5SDavid du Colombier 		close(fd);
30263afb9a5SDavid du Colombier 	}
30363afb9a5SDavid du Colombier 	sig = new_packet(c);
30463afb9a5SDavid du Colombier 	add_string(sig, pkas[c->pkalg]->name);
30563afb9a5SDavid du Colombier 	add_block(sig, sstr, n);
30663afb9a5SDavid du Colombier 	free(sstr);
30763afb9a5SDavid du Colombier 	return sig;
30863afb9a5SDavid du Colombier }
30963afb9a5SDavid du Colombier 
31063afb9a5SDavid du Colombier /*
31163afb9a5SDavid du Colombier  * 0 - If factotum failed, e.g. no key
31263afb9a5SDavid du Colombier  * 1 - If key is verified
31363afb9a5SDavid du Colombier  * -1 - If factotum found a key, but the verification fails
31463afb9a5SDavid du Colombier  */
31563afb9a5SDavid du Colombier static int
rsa_verify(Conn * c,uchar * m,int nm,char * user,char * sig,int)31663afb9a5SDavid du Colombier rsa_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int)
31763afb9a5SDavid du Colombier {
31863afb9a5SDavid du Colombier 	int fd, n, retval, nbit;
31963afb9a5SDavid du Colombier 	char *buf, *p, *sigblob;
32063afb9a5SDavid du Colombier 	uchar *sstr, *em;
32163afb9a5SDavid du Colombier 	uchar hh[SHA1dlen];
32263afb9a5SDavid du Colombier 	mpint *s, *mm, *rsa_exponent, *host_modulus;
32363afb9a5SDavid du Colombier 	AuthRpc *ar;
32463afb9a5SDavid du Colombier 
32563afb9a5SDavid du Colombier 	sshdebug(c, "in rsa_verify for connection: %d", c->id);
32663afb9a5SDavid du Colombier 	SET(rsa_exponent, host_modulus);
32763afb9a5SDavid du Colombier 	USED(rsa_exponent, host_modulus);
32863afb9a5SDavid du Colombier 	if (0 && rsa_exponent) {
32963afb9a5SDavid du Colombier 		nbit = mpsignif(host_modulus);
33063afb9a5SDavid du Colombier 		n = (nbit + 7) / 8;
33163afb9a5SDavid du Colombier 		em = emalloc9p(n);
33263afb9a5SDavid du Colombier 		/* Compute s: RFC 3447 */
33363afb9a5SDavid du Colombier 		esma_encode(m, em, n);
33463afb9a5SDavid du Colombier 		mm = betomp(em, n, nil);
33563afb9a5SDavid du Colombier 		s = mpnew(1024);
33663afb9a5SDavid du Colombier 		mpexp(mm, rsa_exponent, host_modulus, s);
33763afb9a5SDavid du Colombier 		sstr = emalloc9p(n);
33863afb9a5SDavid du Colombier 		mptobe(s, sstr, n, nil);
33963afb9a5SDavid du Colombier 		free(em);
34063afb9a5SDavid du Colombier 		mpfree(mm);
34163afb9a5SDavid du Colombier 		mpfree(s);
34263afb9a5SDavid du Colombier 		retval = memcmp(sig, sstr, n);
34363afb9a5SDavid du Colombier 		free(sstr);
34463afb9a5SDavid du Colombier 		retval = (retval == 0);
34563afb9a5SDavid du Colombier 	} else {
34663afb9a5SDavid du Colombier 		retval = 1;
34763afb9a5SDavid du Colombier 		fd = open("/mnt/factotum/rpc", ORDWR);
34863afb9a5SDavid du Colombier 		if (fd < 0) {
34963afb9a5SDavid du Colombier 			sshdebug(c, "could not open factotum RPC: %r");
35063afb9a5SDavid du Colombier 			return 0;
35163afb9a5SDavid du Colombier 		}
35263afb9a5SDavid du Colombier 		buf = emalloc9p(Blobsz / 2);
35363afb9a5SDavid du Colombier 		sigblob = emalloc9p(Blobsz);
35463afb9a5SDavid du Colombier 		p = (char *)get_string(nil, (uchar *)sig, buf, Blobsz / 2, nil);
35563afb9a5SDavid du Colombier 		get_string(nil, (uchar *)p, sigblob, Blobsz, &n);
35663afb9a5SDavid du Colombier 		sha1(m, nm, hh, nil);
35763afb9a5SDavid du Colombier 		if (user != nil)
35863afb9a5SDavid du Colombier 			p = smprint("role=verify proto=rsa user=%s", user);
35963afb9a5SDavid du Colombier 		else
36063afb9a5SDavid du Colombier 			p = smprint("role=verify proto=rsa sys=%s", c->remote);
36163afb9a5SDavid du Colombier 
36263afb9a5SDavid du Colombier 		ar = auth_allocrpc(fd);
36363afb9a5SDavid du Colombier 		if (ar == nil || auth_rpc(ar, "start", p, strlen(p)) != ARok ||
36463afb9a5SDavid du Colombier 		    auth_rpc(ar, "write", hh, SHA1dlen) != ARok ||
36563afb9a5SDavid du Colombier 		    auth_rpc(ar, "write", sigblob, n) != ARok ||
36663afb9a5SDavid du Colombier 		    auth_rpc(ar, "read", nil, 0) != ARok) {
36763afb9a5SDavid du Colombier 			sshdebug(c, "got error in factotum: %r");
36863afb9a5SDavid du Colombier 			retval = 0;
36963afb9a5SDavid du Colombier 		} else {
37063afb9a5SDavid du Colombier 			sshdebug(c, "factotum returned %s", ar->ibuf);
37163afb9a5SDavid du Colombier 			if (strstr(ar->ibuf, "does not verify") != nil)
37263afb9a5SDavid du Colombier 				retval = -1;
37363afb9a5SDavid du Colombier 		}
37463afb9a5SDavid du Colombier 		if (ar != nil)
37563afb9a5SDavid du Colombier 			auth_freerpc(ar);
37663afb9a5SDavid du Colombier 		free(p);
37763afb9a5SDavid du Colombier 		close(fd);
37863afb9a5SDavid du Colombier 		free(sigblob);
37963afb9a5SDavid du Colombier 		free(buf);
38063afb9a5SDavid du Colombier 	}
38163afb9a5SDavid du Colombier 	return retval;
38263afb9a5SDavid du Colombier }
38363afb9a5SDavid du Colombier 
38463afb9a5SDavid du Colombier static Packet *
dss_ks(Conn * c)38563afb9a5SDavid du Colombier dss_ks(Conn *c)
38663afb9a5SDavid du Colombier {
38763afb9a5SDavid du Colombier 	Packet *ks;
38863afb9a5SDavid du Colombier 
38963afb9a5SDavid du Colombier 	if (mydsskey.pub.p == nil)
39063afb9a5SDavid du Colombier 		return nil;
39163afb9a5SDavid du Colombier 	ks = new_packet(c);
39263afb9a5SDavid du Colombier 	add_string(ks, "ssh-dss");
39363afb9a5SDavid du Colombier 	add_mp(ks, mydsskey.pub.p);
39463afb9a5SDavid du Colombier 	add_mp(ks, mydsskey.pub.q);
39563afb9a5SDavid du Colombier 	add_mp(ks, mydsskey.pub.alpha);
39663afb9a5SDavid du Colombier 	add_mp(ks, mydsskey.pub.key);
39763afb9a5SDavid du Colombier 	return ks;
39863afb9a5SDavid du Colombier }
39963afb9a5SDavid du Colombier 
40063afb9a5SDavid du Colombier static Packet *
dss_sign(Conn * c,uchar * m,int nm)40163afb9a5SDavid du Colombier dss_sign(Conn *c, uchar *m, int nm)
40263afb9a5SDavid du Colombier {
40363afb9a5SDavid du Colombier 	AuthRpc *ar;
40463afb9a5SDavid du Colombier 	DSAsig *s;
40563afb9a5SDavid du Colombier 	Packet *sig;
40663afb9a5SDavid du Colombier 	mpint *mm;
40763afb9a5SDavid du Colombier 	int fd;
40863afb9a5SDavid du Colombier 	uchar sstr[2*SHA1dlen];
40963afb9a5SDavid du Colombier 
41063afb9a5SDavid du Colombier 	sha1(m, nm, sstr, nil);
41163afb9a5SDavid du Colombier 	sig = new_packet(c);
41263afb9a5SDavid du Colombier 	add_string(sig, pkas[c->pkalg]->name);
41363afb9a5SDavid du Colombier 	if (mydsskey.secret) {
41463afb9a5SDavid du Colombier 		mm = betomp(sstr, SHA1dlen, nil);
41563afb9a5SDavid du Colombier 		s = dsasign(&mydsskey, mm);
41663afb9a5SDavid du Colombier 		mptobe(s->r, sstr, SHA1dlen, nil);
41763afb9a5SDavid du Colombier 		mptobe(s->s, sstr+SHA1dlen, SHA1dlen, nil);
41863afb9a5SDavid du Colombier 		dsasigfree(s);
41963afb9a5SDavid du Colombier 		mpfree(mm);
42063afb9a5SDavid du Colombier 	} else {
42163afb9a5SDavid du Colombier 		fd = open("/mnt/factotum/rpc", ORDWR);
42263afb9a5SDavid du Colombier 		if (fd < 0)
42363afb9a5SDavid du Colombier 			return nil;
42463afb9a5SDavid du Colombier 		ar = auth_allocrpc(fd);
42563afb9a5SDavid du Colombier 		if (ar == nil ||
42663afb9a5SDavid du Colombier 		    auth_rpc(ar, "start", "role=sign proto=dsa", 19) != ARok ||
42763afb9a5SDavid du Colombier 		    auth_rpc(ar, "write", sstr, SHA1dlen) != ARok ||
42863afb9a5SDavid du Colombier 		    auth_rpc(ar, "read", nil, 0) != ARok) {
42963afb9a5SDavid du Colombier 			sshdebug(c, "got error in factotum: %r");
43063afb9a5SDavid du Colombier 			auth_freerpc(ar);
43163afb9a5SDavid du Colombier 			close(fd);
43263afb9a5SDavid du Colombier 			return nil;
43363afb9a5SDavid du Colombier 		}
43463afb9a5SDavid du Colombier 		memmove(sstr, ar->arg, ar->narg);
43563afb9a5SDavid du Colombier 		auth_freerpc(ar);
43663afb9a5SDavid du Colombier 		close(fd);
43763afb9a5SDavid du Colombier 	}
43863afb9a5SDavid du Colombier 	add_block(sig, sstr, 2*SHA1dlen);
43963afb9a5SDavid du Colombier 	return sig;
44063afb9a5SDavid du Colombier }
44163afb9a5SDavid du Colombier 
44263afb9a5SDavid du Colombier static int
dss_verify(Conn * c,uchar * m,int nm,char * user,char * sig,int nsig)44363afb9a5SDavid du Colombier dss_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int nsig)
44463afb9a5SDavid du Colombier {
44563afb9a5SDavid du Colombier 	sshdebug(c, "in dss_verify for connection: %d", c->id);
44663afb9a5SDavid du Colombier 	USED(m, nm, user, sig, nsig);
44763afb9a5SDavid du Colombier 	return 0;
44863afb9a5SDavid du Colombier }
44963afb9a5SDavid du Colombier 
45063afb9a5SDavid du Colombier static int
dh_server1(Conn * c,Packet * pack1)45163afb9a5SDavid du Colombier dh_server1(Conn *c, Packet *pack1)
45263afb9a5SDavid du Colombier {
45363afb9a5SDavid du Colombier 	return dh_server(c, pack1, p1, 1024);
45463afb9a5SDavid du Colombier }
45563afb9a5SDavid du Colombier 
45663afb9a5SDavid du Colombier static int
dh_server14(Conn * c,Packet * pack1)45763afb9a5SDavid du Colombier dh_server14(Conn *c, Packet *pack1)
45863afb9a5SDavid du Colombier {
45963afb9a5SDavid du Colombier 	return dh_server(c, pack1, p14, 2048);
46063afb9a5SDavid du Colombier }
46163afb9a5SDavid du Colombier 
46263afb9a5SDavid du Colombier static int
dh_server(Conn * c,Packet * pack1,mpint * grp,int nbit)46363afb9a5SDavid du Colombier dh_server(Conn *c, Packet *pack1, mpint *grp, int nbit)
46463afb9a5SDavid du Colombier {
46563afb9a5SDavid du Colombier 	Packet *pack2, *ks, *sig;
46663afb9a5SDavid du Colombier 	mpint *y, *e, *f, *k;
46763afb9a5SDavid du Colombier 	int n, ret;
46863afb9a5SDavid du Colombier 	uchar h[SHA1dlen];
46963afb9a5SDavid du Colombier 
47063afb9a5SDavid du Colombier 	ret = -1;
47163afb9a5SDavid du Colombier 	qlock(&c->l);
47263afb9a5SDavid du Colombier 	f = mpnew(nbit);
47363afb9a5SDavid du Colombier 	k = mpnew(nbit);
47463afb9a5SDavid du Colombier 
47563afb9a5SDavid du Colombier 	/* Compute f: RFC4253 */
47663afb9a5SDavid du Colombier 	y = mprand(nbit / 8, genrandom, nil);
47763afb9a5SDavid du Colombier 	if (debug > 1)
47863afb9a5SDavid du Colombier 		sshdebug(c, "y=%M", y);
47963afb9a5SDavid du Colombier 	mpexp(two, y, grp, f);
48063afb9a5SDavid du Colombier 	if (debug > 1)
48163afb9a5SDavid du Colombier 		sshdebug(c, "f=%M", f);
48263afb9a5SDavid du Colombier 
48363afb9a5SDavid du Colombier 	/* Compute k: RFC4253 */
48463afb9a5SDavid du Colombier 	if (debug > 1)
48563afb9a5SDavid du Colombier 		dump_packet(pack1);
48663afb9a5SDavid du Colombier 	e = get_mp(pack1->payload+1);
48763afb9a5SDavid du Colombier 	if (debug > 1)
48863afb9a5SDavid du Colombier 		sshdebug(c, "e=%M", e);
48963afb9a5SDavid du Colombier 	mpexp(e, y, grp, k);
49063afb9a5SDavid du Colombier 	if (debug > 1)
49163afb9a5SDavid du Colombier 		sshdebug(c, "k=%M", k);
49263afb9a5SDavid du Colombier 
49363afb9a5SDavid du Colombier 	/* Compute H: RFC 4253 */
49463afb9a5SDavid du Colombier 	pack2 = new_packet(c);
49563afb9a5SDavid du Colombier 	sshdebug(c, "ID strings: %s---%s", c->otherid, MYID);
49663afb9a5SDavid du Colombier 	add_string(pack2, c->otherid);
49763afb9a5SDavid du Colombier 	add_string(pack2, MYID);
49863afb9a5SDavid du Colombier 	if (debug > 1) {
49963afb9a5SDavid du Colombier 		fprint(2, "received kexinit:");
50063afb9a5SDavid du Colombier 		dump_packet(c->rkexinit);
50163afb9a5SDavid du Colombier 		fprint(2, "\nsent kexinit:");
50263afb9a5SDavid du Colombier 		dump_packet(c->skexinit);
50363afb9a5SDavid du Colombier 	}
50463afb9a5SDavid du Colombier 	add_block(pack2, c->rkexinit->payload, c->rkexinit->rlength - 1);
50563afb9a5SDavid du Colombier 	add_block(pack2, c->skexinit->payload,
50663afb9a5SDavid du Colombier 		c->skexinit->rlength - c->skexinit->pad_len - 1);
50763afb9a5SDavid du Colombier 	sig = nil;
50863afb9a5SDavid du Colombier 	ks = pkas[c->pkalg]->ks(c);
50963afb9a5SDavid du Colombier 	if (ks == nil)
51063afb9a5SDavid du Colombier 		goto err;
51163afb9a5SDavid du Colombier 	add_block(pack2, ks->payload, ks->rlength - 1);
51263afb9a5SDavid du Colombier 	add_mp(pack2, e);
51363afb9a5SDavid du Colombier 	add_mp(pack2, f);
51463afb9a5SDavid du Colombier 	add_mp(pack2, k);
51563afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, h, nil);
51663afb9a5SDavid du Colombier 
51763afb9a5SDavid du Colombier 	if (c->got_sessid == 0) {
51863afb9a5SDavid du Colombier 		memmove(c->sessid, h, SHA1dlen);
51963afb9a5SDavid du Colombier 		c->got_sessid = 1;
52063afb9a5SDavid du Colombier 	}
52163afb9a5SDavid du Colombier 	sig = pkas[c->pkalg]->sign(c, h, SHA1dlen);
52263afb9a5SDavid du Colombier 	if (sig == nil) {
52363afb9a5SDavid du Colombier 		sshlog(c, "failed to generate signature: %r");
52463afb9a5SDavid du Colombier 		goto err;
52563afb9a5SDavid du Colombier 	}
52663afb9a5SDavid du Colombier 
52763afb9a5SDavid du Colombier 	/* Send (K_s || f || s) to client: RFC4253 */
52863afb9a5SDavid du Colombier 	init_packet(pack2);
52963afb9a5SDavid du Colombier 	pack2->c = c;
53063afb9a5SDavid du Colombier 	add_byte(pack2, SSH_MSG_KEXDH_REPLY);
53163afb9a5SDavid du Colombier 	add_block(pack2, ks->payload, ks->rlength - 1);
53263afb9a5SDavid du Colombier 	add_mp(pack2, f);
53363afb9a5SDavid du Colombier 	add_block(pack2, sig->payload, sig->rlength - 1);
53463afb9a5SDavid du Colombier 	if (debug > 1)
53563afb9a5SDavid du Colombier 		dump_packet(pack2);
53663afb9a5SDavid du Colombier 	n = finish_packet(pack2);
53763afb9a5SDavid du Colombier 	if (debug > 1) {
53863afb9a5SDavid du Colombier 		sshdebug(c, "writing %d bytes: len %d", n, nhgetl(pack2->nlength));
53963afb9a5SDavid du Colombier 		dump_packet(pack2);
54063afb9a5SDavid du Colombier 	}
54163afb9a5SDavid du Colombier 	iowrite(c->dio, c->datafd, pack2->nlength, n);
54263afb9a5SDavid du Colombier 
54363afb9a5SDavid du Colombier 	genkeys(c, h, k);
54463afb9a5SDavid du Colombier 
54563afb9a5SDavid du Colombier 	/* Send SSH_MSG_NEWKEYS */
54663afb9a5SDavid du Colombier 	init_packet(pack2);
54763afb9a5SDavid du Colombier 	pack2->c = c;
54863afb9a5SDavid du Colombier 	add_byte(pack2, SSH_MSG_NEWKEYS);
54963afb9a5SDavid du Colombier 	n = finish_packet(pack2);
55063afb9a5SDavid du Colombier 	iowrite(c->dio, c->datafd, pack2->nlength, n);
55163afb9a5SDavid du Colombier 	ret = 0;
55263afb9a5SDavid du Colombier err:
55363afb9a5SDavid du Colombier 	mpfree(f);
55463afb9a5SDavid du Colombier 	mpfree(e);
55563afb9a5SDavid du Colombier 	mpfree(k);
55663afb9a5SDavid du Colombier 	mpfree(y);
55763afb9a5SDavid du Colombier 	free(sig);
55863afb9a5SDavid du Colombier 	free(ks);
55963afb9a5SDavid du Colombier 	free(pack2);
56063afb9a5SDavid du Colombier 	qunlock(&c->l);
56163afb9a5SDavid du Colombier 	return ret;
56263afb9a5SDavid du Colombier }
56363afb9a5SDavid du Colombier 
56463afb9a5SDavid du Colombier static int
dh_client11(Conn * c,Packet *)56563afb9a5SDavid du Colombier dh_client11(Conn *c, Packet *)
56663afb9a5SDavid du Colombier {
567*c59d18e2SDavid du Colombier 	return dh_client1(c, p1, 128, 1024);
568*c59d18e2SDavid du Colombier }
569*c59d18e2SDavid du Colombier 
570*c59d18e2SDavid du Colombier static int
dh_client141(Conn * c,Packet *)571*c59d18e2SDavid du Colombier dh_client141(Conn *c, Packet *)
572*c59d18e2SDavid du Colombier {
573*c59d18e2SDavid du Colombier 	return dh_client1(c, p14, 256, 2014);
574*c59d18e2SDavid du Colombier }
575*c59d18e2SDavid du Colombier 
576*c59d18e2SDavid du Colombier static int
dh_client1(Conn * c,mpint * grp,int nrand,int nbit)577*c59d18e2SDavid du Colombier dh_client1(Conn *c, mpint *grp, int nrand, int nbit)
578*c59d18e2SDavid du Colombier {
57963afb9a5SDavid du Colombier 	Packet *p;
58063afb9a5SDavid du Colombier 	int n;
58163afb9a5SDavid du Colombier 
58263afb9a5SDavid du Colombier 	if (c->e)
58363afb9a5SDavid du Colombier 		mpfree(c->e);
584*c59d18e2SDavid du Colombier 	c->e = mpnew(nbit);
58563afb9a5SDavid du Colombier 
58663afb9a5SDavid du Colombier 	/* Compute e: RFC4253 */
58763afb9a5SDavid du Colombier 	if (c->x)
58863afb9a5SDavid du Colombier 		mpfree(c->x);
589*c59d18e2SDavid du Colombier 	c->x = mprand(nrand, genrandom, nil);
590*c59d18e2SDavid du Colombier 	mpexp(two, c->x, grp, c->e);
59163afb9a5SDavid du Colombier 
59263afb9a5SDavid du Colombier 	p = new_packet(c);
59363afb9a5SDavid du Colombier 	add_byte(p, SSH_MSG_KEXDH_INIT);
59463afb9a5SDavid du Colombier 	add_mp(p, c->e);
59563afb9a5SDavid du Colombier 	n = finish_packet(p);
59663afb9a5SDavid du Colombier 	iowrite(c->dio, c->datafd, p->nlength, n);
59763afb9a5SDavid du Colombier 	free(p);
59863afb9a5SDavid du Colombier 	return 0;
59963afb9a5SDavid du Colombier }
60063afb9a5SDavid du Colombier 
60163afb9a5SDavid du Colombier static int
findkeyinuserring(Conn * c,RSApub * srvkey)60263afb9a5SDavid du Colombier findkeyinuserring(Conn *c, RSApub *srvkey)
60363afb9a5SDavid du Colombier {
60463afb9a5SDavid du Colombier 	int n;
60563afb9a5SDavid du Colombier 	char *home, *newkey, *r;
60663afb9a5SDavid du Colombier 
60763afb9a5SDavid du Colombier 	home = getenv("home");
60863afb9a5SDavid du Colombier 	if (home == nil) {
60963afb9a5SDavid du Colombier 		newkey = "No home directory for key file";
61063afb9a5SDavid du Colombier 		free(keymbox.msg);
61163afb9a5SDavid du Colombier 		keymbox.msg = smprint("b%04ld%s", strlen(newkey), newkey);
61263afb9a5SDavid du Colombier 		return -1;
61363afb9a5SDavid du Colombier 	}
61463afb9a5SDavid du Colombier 
61563afb9a5SDavid du Colombier 	r = smprint("%s/lib/keyring", home);
61663afb9a5SDavid du Colombier 	free(home);
61763afb9a5SDavid du Colombier 	if ((n = findkey(r, c->remote, srvkey)) != KeyOk) {
61863afb9a5SDavid du Colombier 		newkey = smprint("ek=%M n=%M", srvkey->ek, srvkey->n);
61963afb9a5SDavid du Colombier 		free(keymbox.msg);
62063afb9a5SDavid du Colombier 		keymbox.msg = smprint("%c%04ld%s", n == NoKeyFile || n == NoKey?
62163afb9a5SDavid du Colombier 			'c': 'b', strlen(newkey), newkey);
62263afb9a5SDavid du Colombier 		free(newkey);
62363afb9a5SDavid du Colombier 
62463afb9a5SDavid du Colombier 		nbsendul(keymbox.mchan, 1);
62563afb9a5SDavid du Colombier 		recvul(keymbox.mchan);
62663afb9a5SDavid du Colombier 		if (keymbox.msg == nil || keymbox.msg[0] == 'n') {
62763afb9a5SDavid du Colombier 			free(keymbox.msg);
62863afb9a5SDavid du Colombier 			keymbox.msg = nil;
62963afb9a5SDavid du Colombier 			newkey = "Server key reject";
63063afb9a5SDavid du Colombier 			keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
63163afb9a5SDavid du Colombier 			return -1;
63263afb9a5SDavid du Colombier 		}
63363afb9a5SDavid du Colombier 		sshdebug(c, "adding key");
63463afb9a5SDavid du Colombier 		if (keymbox.msg[0] == 'y')
63563afb9a5SDavid du Colombier 			appendkey(r, c->remote, srvkey);
63663afb9a5SDavid du Colombier 		else if (keymbox.msg[0] == 'r')
63763afb9a5SDavid du Colombier 			replacekey(r, c->remote, srvkey);
63863afb9a5SDavid du Colombier 	}
63963afb9a5SDavid du Colombier 	free(r);
64063afb9a5SDavid du Colombier 	return 0;
64163afb9a5SDavid du Colombier }
64263afb9a5SDavid du Colombier 
64363afb9a5SDavid du Colombier static int
verifyhostkey(Conn * c,RSApub * srvkey,Packet * sig)64463afb9a5SDavid du Colombier verifyhostkey(Conn *c, RSApub *srvkey, Packet *sig)
64563afb9a5SDavid du Colombier {
64663afb9a5SDavid du Colombier 	int fd, n;
64763afb9a5SDavid du Colombier 	char *newkey;
64863afb9a5SDavid du Colombier 	uchar h[SHA1dlen];
64963afb9a5SDavid du Colombier 
65063afb9a5SDavid du Colombier 	sshdebug(c, "verifying server signature");
65163afb9a5SDavid du Colombier 	if (findkey("/sys/lib/ssh/keyring", c->remote, srvkey) != KeyOk &&
65263afb9a5SDavid du Colombier 	    findkeyinuserring(c, srvkey) < 0) {
65363afb9a5SDavid du Colombier 		nbsendul(keymbox.mchan, 1);
65463afb9a5SDavid du Colombier 		mpfree(srvkey->ek);
65563afb9a5SDavid du Colombier 		mpfree(srvkey->n);
656998526ebSDavid du Colombier 		return Errnokey;
65763afb9a5SDavid du Colombier 	}
65863afb9a5SDavid du Colombier 
65963afb9a5SDavid du Colombier 	newkey = smprint("key proto=rsa role=verify sys=%s size=%d ek=%M n=%M",
66063afb9a5SDavid du Colombier 		c->remote, mpsignif(srvkey->n), srvkey->ek, srvkey->n);
66163afb9a5SDavid du Colombier 	if (newkey == nil) {
66263afb9a5SDavid du Colombier 		sshlog(c, "out of memory");
663998526ebSDavid du Colombier 		threadexits("out of memory");
66463afb9a5SDavid du Colombier 	}
66563afb9a5SDavid du Colombier 
66663afb9a5SDavid du Colombier 	fd = open("/mnt/factotum/ctl", OWRITE);
66763afb9a5SDavid du Colombier 	if (fd >= 0)
66863afb9a5SDavid du Colombier 		write(fd, newkey, strlen(newkey));
66963afb9a5SDavid du Colombier 		/* leave fd open */
67063afb9a5SDavid du Colombier 	else
67163afb9a5SDavid du Colombier 		sshdebug(c, "factotum open failed: %r");
67263afb9a5SDavid du Colombier 
67363afb9a5SDavid du Colombier 	free(newkey);
67463afb9a5SDavid du Colombier 	mpfree(srvkey->ek);
67563afb9a5SDavid du Colombier 	mpfree(srvkey->n);
67663afb9a5SDavid du Colombier 	free(keymbox.msg);
67763afb9a5SDavid du Colombier 	keymbox.msg = nil;
67863afb9a5SDavid du Colombier 
67963afb9a5SDavid du Colombier 	n = pkas[c->pkalg]->verify(c, h, SHA1dlen, nil, (char *)sig->payload,
68063afb9a5SDavid du Colombier 		sig->rlength);
68163afb9a5SDavid du Colombier 
68263afb9a5SDavid du Colombier 	/* fd is perhaps still open */
68363afb9a5SDavid du Colombier 	if (fd >= 0) {
68463afb9a5SDavid du Colombier 		/* sys here is a dotted-quad ip address */
68563afb9a5SDavid du Colombier 		newkey = smprint("delkey proto=rsa role=verify sys=%s",
68663afb9a5SDavid du Colombier 			c->remote);
68763afb9a5SDavid du Colombier 		if (newkey) {
68863afb9a5SDavid du Colombier 			seek(fd, 0, 0);
68963afb9a5SDavid du Colombier 			write(fd, newkey, strlen(newkey));
69063afb9a5SDavid du Colombier 			free(newkey);
69163afb9a5SDavid du Colombier 		}
69263afb9a5SDavid du Colombier 		close(fd);
69363afb9a5SDavid du Colombier 	}
69463afb9a5SDavid du Colombier 	return n;
69563afb9a5SDavid du Colombier }
69663afb9a5SDavid du Colombier 
69763afb9a5SDavid du Colombier static int
dh_client12(Conn * c,Packet * p)69863afb9a5SDavid du Colombier dh_client12(Conn *c, Packet *p)
69963afb9a5SDavid du Colombier {
700*c59d18e2SDavid du Colombier 	return dh_client2(c, p, p1, 1024);
701*c59d18e2SDavid du Colombier }
702*c59d18e2SDavid du Colombier 
703*c59d18e2SDavid du Colombier static int
dh_client142(Conn * c,Packet * p)704*c59d18e2SDavid du Colombier dh_client142(Conn *c, Packet *p)
705*c59d18e2SDavid du Colombier {
706*c59d18e2SDavid du Colombier 	return dh_client2(c, p, p14, 2048);
707*c59d18e2SDavid du Colombier }
708*c59d18e2SDavid du Colombier 
709*c59d18e2SDavid du Colombier static int
dh_client2(Conn * c,Packet * p,mpint * grp,int nbits)710*c59d18e2SDavid du Colombier dh_client2(Conn *c, Packet *p, mpint *grp, int nbits)
711*c59d18e2SDavid du Colombier {
71263afb9a5SDavid du Colombier 	int n, retval;
71348207d97SDavid du Colombier #ifdef VERIFYKEYS
71463afb9a5SDavid du Colombier 	char *newkey;
71548207d97SDavid du Colombier #endif
71663afb9a5SDavid du Colombier 	char buf[10];
71763afb9a5SDavid du Colombier 	uchar *q;
71863afb9a5SDavid du Colombier 	uchar h[SHA1dlen];
71963afb9a5SDavid du Colombier 	mpint *f, *k;
72063afb9a5SDavid du Colombier 	Packet *ks, *sig, *pack2;
72163afb9a5SDavid du Colombier 	RSApub *srvkey;
72263afb9a5SDavid du Colombier 
72363afb9a5SDavid du Colombier 	ks = new_packet(c);
72463afb9a5SDavid du Colombier 	sig = new_packet(c);
72563afb9a5SDavid du Colombier 	pack2 = new_packet(c);
72663afb9a5SDavid du Colombier 
72763afb9a5SDavid du Colombier 	q = get_string(p, p->payload+1, (char *)ks->payload, Maxpktpay, &n);
72863afb9a5SDavid du Colombier 	ks->rlength = n + 1;
72963afb9a5SDavid du Colombier 	f = get_mp(q);
73063afb9a5SDavid du Colombier 	q += nhgetl(q) + 4;
73163afb9a5SDavid du Colombier 	get_string(p, q, (char *)sig->payload, Maxpktpay, &n);
73263afb9a5SDavid du Colombier 	sig->rlength = n;
733*c59d18e2SDavid du Colombier 	k = mpnew(nbits);
734*c59d18e2SDavid du Colombier 	mpexp(f, c->x, grp, k);
73563afb9a5SDavid du Colombier 
73663afb9a5SDavid du Colombier 	/* Compute H: RFC 4253 */
73763afb9a5SDavid du Colombier 	init_packet(pack2);
73863afb9a5SDavid du Colombier 	pack2->c = c;
73963afb9a5SDavid du Colombier 	if (debug > 1)
74063afb9a5SDavid du Colombier 		sshdebug(c, "ID strings: %s---%s", c->otherid, MYID);
74163afb9a5SDavid du Colombier 	add_string(pack2, MYID);
74263afb9a5SDavid du Colombier 	add_string(pack2, c->otherid);
74363afb9a5SDavid du Colombier 	if (debug > 1) {
74463afb9a5SDavid du Colombier 		fprint(2, "received kexinit:");
74563afb9a5SDavid du Colombier 		dump_packet(c->rkexinit);
74663afb9a5SDavid du Colombier 		fprint(2, "\nsent kexinit:");
74763afb9a5SDavid du Colombier 		dump_packet(c->skexinit);
74863afb9a5SDavid du Colombier 	}
74963afb9a5SDavid du Colombier 	add_block(pack2, c->skexinit->payload,
75063afb9a5SDavid du Colombier 		c->skexinit->rlength - c->skexinit->pad_len - 1);
75163afb9a5SDavid du Colombier 	add_block(pack2, c->rkexinit->payload, c->rkexinit->rlength - 1);
75263afb9a5SDavid du Colombier 	add_block(pack2, ks->payload, ks->rlength - 1);
75363afb9a5SDavid du Colombier 	add_mp(pack2, c->e);
75463afb9a5SDavid du Colombier 	add_mp(pack2, f);
75563afb9a5SDavid du Colombier 	add_mp(pack2, k);
75663afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, h, nil);
75763afb9a5SDavid du Colombier 	mpfree(f);
75863afb9a5SDavid du Colombier 
75963afb9a5SDavid du Colombier 	if (c->got_sessid == 0) {
76063afb9a5SDavid du Colombier 		memmove(c->sessid, h, SHA1dlen);
76163afb9a5SDavid du Colombier 		c->got_sessid = 1;
76263afb9a5SDavid du Colombier 	}
76363afb9a5SDavid du Colombier 
76463afb9a5SDavid du Colombier 	q = get_string(ks, ks->payload, buf, sizeof buf, nil);
76563afb9a5SDavid du Colombier 	srvkey = emalloc9p(sizeof (RSApub));
76663afb9a5SDavid du Colombier 	srvkey->ek = get_mp(q);
76763afb9a5SDavid du Colombier 	q += nhgetl(q) + 4;
76863afb9a5SDavid du Colombier 	srvkey->n = get_mp(q);
76963afb9a5SDavid du Colombier 
77063afb9a5SDavid du Colombier 	/*
77163afb9a5SDavid du Colombier 	 * key verification is really pretty pedantic and
77263afb9a5SDavid du Colombier 	 * not doing it lets us talk to ssh v1 implementations.
77363afb9a5SDavid du Colombier 	 */
77463afb9a5SDavid du Colombier 	if (nokeyverify)
775998526ebSDavid du Colombier 		n = Errnone;
77663afb9a5SDavid du Colombier 	else
77763afb9a5SDavid du Colombier 		n = verifyhostkey(c, srvkey, sig);
77848207d97SDavid du Colombier 	retval = -1;
77948207d97SDavid du Colombier 	USED(retval);
78063afb9a5SDavid du Colombier 	switch (n) {
781998526ebSDavid du Colombier #ifdef VERIFYKEYS
782998526ebSDavid du Colombier 	case Errnokey:
78363afb9a5SDavid du Colombier 		goto out;
784998526ebSDavid du Colombier 	case Errnoverify:
785d7e44d0dSDavid du Colombier 		newkey = "signature verification failed; try netssh -v";
78663afb9a5SDavid du Colombier 		keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
78763afb9a5SDavid du Colombier 		break;
788998526ebSDavid du Colombier 	case Errfactotum:
789998526ebSDavid du Colombier 		newkey = "factotum dialogue failed; try netssh -v";
79063afb9a5SDavid du Colombier 		keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
79163afb9a5SDavid du Colombier 		break;
792998526ebSDavid du Colombier 	case Errnone:
793998526ebSDavid du Colombier #else
794998526ebSDavid du Colombier 	default:
795998526ebSDavid du Colombier #endif
79663afb9a5SDavid du Colombier 		keymbox.msg = smprint("o0000");
79763afb9a5SDavid du Colombier 		retval = 0;
79863afb9a5SDavid du Colombier 		break;
79963afb9a5SDavid du Colombier 	}
80063afb9a5SDavid du Colombier 	nbsendul(keymbox.mchan, 1);
80163afb9a5SDavid du Colombier 	if (retval == 0)
80263afb9a5SDavid du Colombier 		genkeys(c, h, k);
80348207d97SDavid du Colombier #ifdef VERIFYKEYS
80463afb9a5SDavid du Colombier out:
80548207d97SDavid du Colombier #endif
80663afb9a5SDavid du Colombier 	mpfree(k);
80763afb9a5SDavid du Colombier 	free(ks);
80863afb9a5SDavid du Colombier 	free(sig);
80963afb9a5SDavid du Colombier 	free(pack2);
81063afb9a5SDavid du Colombier 	free(srvkey);
81163afb9a5SDavid du Colombier 	return retval;
81263afb9a5SDavid du Colombier }
81363afb9a5SDavid du Colombier 
81463afb9a5SDavid du Colombier static void
initsha1pkt(Packet * pack2,mpint * k,uchar * h)81563afb9a5SDavid du Colombier initsha1pkt(Packet *pack2, mpint *k, uchar *h)
81663afb9a5SDavid du Colombier {
81763afb9a5SDavid du Colombier 	init_packet(pack2);
81863afb9a5SDavid du Colombier 	add_mp(pack2, k);
81963afb9a5SDavid du Colombier 	add_packet(pack2, h, SHA1dlen);
82063afb9a5SDavid du Colombier }
82163afb9a5SDavid du Colombier 
82263afb9a5SDavid du Colombier static void
genkeys(Conn * c,uchar h[],mpint * k)82363afb9a5SDavid du Colombier genkeys(Conn *c, uchar h[], mpint *k)
82463afb9a5SDavid du Colombier {
82563afb9a5SDavid du Colombier 	Packet *pack2;
82663afb9a5SDavid du Colombier 	char buf[82], *bp, *be;			/* magic 82 */
82763afb9a5SDavid du Colombier 	int n;
82863afb9a5SDavid du Colombier 
82963afb9a5SDavid du Colombier 	pack2 = new_packet(c);
83063afb9a5SDavid du Colombier 	/* Compute 40 bytes (320 bits) of keys: each alg can use what it needs */
83163afb9a5SDavid du Colombier 
83263afb9a5SDavid du Colombier 	/* Client to server IV */
83363afb9a5SDavid du Colombier 	if (debug > 1) {
83463afb9a5SDavid du Colombier 		fprint(2, "k=%M\nh=", k);
83563afb9a5SDavid du Colombier 		for (n = 0; n < SHA1dlen; ++n)
83663afb9a5SDavid du Colombier 			fprint(2, "%02ux", h[n]);
83763afb9a5SDavid du Colombier 		fprint(2, "\nsessid=");
83863afb9a5SDavid du Colombier 		for (n = 0; n < SHA1dlen; ++n)
83963afb9a5SDavid du Colombier 			fprint(2, "%02ux", c->sessid[n]);
84063afb9a5SDavid du Colombier 		fprint(2, "\n");
84163afb9a5SDavid du Colombier 	}
84263afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
84363afb9a5SDavid du Colombier 	add_byte(pack2, 'A');
84463afb9a5SDavid du Colombier 	add_packet(pack2, c->sessid, SHA1dlen);
84563afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->nc2siv, nil);
84663afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
84763afb9a5SDavid du Colombier 	add_packet(pack2, c->nc2siv, SHA1dlen);
84863afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->nc2siv + SHA1dlen, nil);
84963afb9a5SDavid du Colombier 
85063afb9a5SDavid du Colombier 	/* Server to client IV */
85163afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
85263afb9a5SDavid du Colombier 	add_byte(pack2, 'B');
85363afb9a5SDavid du Colombier 	add_packet(pack2, c->sessid, SHA1dlen);
85463afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->ns2civ, nil);
85563afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
85663afb9a5SDavid du Colombier 	add_packet(pack2, c->ns2civ, SHA1dlen);
85763afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->ns2civ + SHA1dlen, nil);
85863afb9a5SDavid du Colombier 
85963afb9a5SDavid du Colombier 	/* Client to server encryption key */
86063afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
86163afb9a5SDavid du Colombier 	add_byte(pack2, 'C');
86263afb9a5SDavid du Colombier 	add_packet(pack2, c->sessid, SHA1dlen);
86363afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->nc2sek, nil);
86463afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
86563afb9a5SDavid du Colombier 	add_packet(pack2, c->nc2sek, SHA1dlen);
86663afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->nc2sek + SHA1dlen, nil);
86763afb9a5SDavid du Colombier 
86863afb9a5SDavid du Colombier 	/* Server to client encryption key */
86963afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
87063afb9a5SDavid du Colombier 	add_byte(pack2, 'D');
87163afb9a5SDavid du Colombier 	add_packet(pack2, c->sessid, SHA1dlen);
87263afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->ns2cek, nil);
87363afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
87463afb9a5SDavid du Colombier 	add_packet(pack2, c->ns2cek, SHA1dlen);
87563afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->ns2cek + SHA1dlen, nil);
87663afb9a5SDavid du Colombier 
87763afb9a5SDavid du Colombier 	/* Client to server integrity key */
87863afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
87963afb9a5SDavid du Colombier 	add_byte(pack2, 'E');
88063afb9a5SDavid du Colombier 	add_packet(pack2, c->sessid, SHA1dlen);
88163afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->nc2sik, nil);
88263afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
88363afb9a5SDavid du Colombier 	add_packet(pack2, c->nc2sik, SHA1dlen);
88463afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->nc2sik + SHA1dlen, nil);
88563afb9a5SDavid du Colombier 
88663afb9a5SDavid du Colombier 	/* Server to client integrity key */
88763afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
88863afb9a5SDavid du Colombier 	add_byte(pack2, 'F');
88963afb9a5SDavid du Colombier 	add_packet(pack2, c->sessid, SHA1dlen);
89063afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->ns2cik, nil);
89163afb9a5SDavid du Colombier 	initsha1pkt(pack2, k, h);
89263afb9a5SDavid du Colombier 	add_packet(pack2, c->ns2cik, SHA1dlen);
89363afb9a5SDavid du Colombier 	sha1(pack2->payload, pack2->rlength - 1, c->ns2cik + SHA1dlen, nil);
89463afb9a5SDavid du Colombier 
89563afb9a5SDavid du Colombier 	if (debug > 1) {
89663afb9a5SDavid du Colombier 		be = buf + sizeof buf;
89763afb9a5SDavid du Colombier 		fprint(2, "Client to server IV:\n");
89863afb9a5SDavid du Colombier 		for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
89963afb9a5SDavid du Colombier 			bp = seprint(bp, be, "%02x", c->nc2siv[n]);
90063afb9a5SDavid du Colombier 		fprint(2, "%s\n", buf);
90163afb9a5SDavid du Colombier 
90263afb9a5SDavid du Colombier 		fprint(2, "Server to client IV:\n");
90363afb9a5SDavid du Colombier 		for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
90463afb9a5SDavid du Colombier 			bp = seprint(bp, be, "%02x", c->ns2civ[n]);
90563afb9a5SDavid du Colombier 		fprint(2, "%s\n", buf);
90663afb9a5SDavid du Colombier 
90763afb9a5SDavid du Colombier 		fprint(2, "Client to server EK:\n");
90863afb9a5SDavid du Colombier 		for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
90963afb9a5SDavid du Colombier 			bp = seprint(bp, be, "%02x", c->nc2sek[n]);
91063afb9a5SDavid du Colombier 		fprint(2, "%s\n", buf);
91163afb9a5SDavid du Colombier 
91263afb9a5SDavid du Colombier 		fprint(2, "Server to client EK:\n");
91363afb9a5SDavid du Colombier 		for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
91463afb9a5SDavid du Colombier 			bp = seprint(bp, be, "%02x", c->ns2cek[n]);
91563afb9a5SDavid du Colombier 		fprint(2, "%s\n", buf);
91663afb9a5SDavid du Colombier 	}
91763afb9a5SDavid du Colombier 	free(pack2);
91863afb9a5SDavid du Colombier }
91963afb9a5SDavid du Colombier 
92063afb9a5SDavid du Colombier Kex dh1sha1 = {
92163afb9a5SDavid du Colombier 	"diffie-hellman-group1-sha1",
92263afb9a5SDavid du Colombier 	dh_server1,
92363afb9a5SDavid du Colombier 	dh_client11,
92463afb9a5SDavid du Colombier 	dh_client12
92563afb9a5SDavid du Colombier };
92663afb9a5SDavid du Colombier 
92763afb9a5SDavid du Colombier Kex dh14sha1 = {
92863afb9a5SDavid du Colombier 	"diffie-hellman-group14-sha1",
92963afb9a5SDavid du Colombier 	dh_server14,
93063afb9a5SDavid du Colombier 	dh_client141,
93163afb9a5SDavid du Colombier 	dh_client142
93263afb9a5SDavid du Colombier };
93363afb9a5SDavid du Colombier 
93463afb9a5SDavid du Colombier PKA rsa_pka = {
93563afb9a5SDavid du Colombier 	"ssh-rsa",
93663afb9a5SDavid du Colombier 	rsa_ks,
93763afb9a5SDavid du Colombier 	rsa_sign,
93863afb9a5SDavid du Colombier 	rsa_verify
93963afb9a5SDavid du Colombier };
94063afb9a5SDavid du Colombier 
94163afb9a5SDavid du Colombier PKA dss_pka = {
94263afb9a5SDavid du Colombier 	"ssh-dss",
94363afb9a5SDavid du Colombier 	dss_ks,
94463afb9a5SDavid du Colombier 	dss_sign,
94563afb9a5SDavid du Colombier 	dss_verify
94663afb9a5SDavid du Colombier };
947