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