917 lines · 20.9 KB · C
RawDownload
#include <u.h>#include <libc.h>#include <mp.h>#include <libsec.h>#include <fcall.h>#include <thread.h>#include <9p.h>#include <auth.h>#include <ip.h>#include <pool.h>#include "sshtun.h" static int dh_server(Conn *, Packet *, mpint *, int);static void genkeys(Conn *, uchar [], mpint *); /* * Second Oakley Group from RFC 2409 */static char *group1p =         "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"         "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"         "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"         "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"         "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"         "FFFFFFFFFFFFFFFF"; /* * 2048-bit MODP group (id 14) from RFC 3526*/static char *group14p =      "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"      "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"      "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"      "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"      "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"      "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"      "83655D23DCA3AD961C62F356208552BB9ED529077096966D"      "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"      "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"      "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"      "15728E5A8AACAA68FFFFFFFFFFFFFFFF";  mpint *two, *p1, *p14;static DSApriv mydsskey;static RSApriv myrsakey; voiddh_init(PKA *pkas[]){	char *p, *st, *end;	int fd, n, k;	char *buf; 	buf = emalloc9p(4096);	k = 0;	pkas[k] = nil;	st = buf;	end = buf + 4096;	fmtinstall('M', mpfmt);	two = strtomp("2", nil, 10, nil);	p1 = strtomp(group1p, nil, 16, nil);	p14 = strtomp(group14p, nil, 16, nil);	/*	 * this really should be done through factotum	 */	p = getenv("rsakey");	if (p == nil) {		fd = open("rsakey", OREAD);		if (fd < 0) {			fd = open("/mnt/factotum/ctl", OREAD);			if (fd < 0)				goto initdss;		}		n = read(fd, buf, 4095);		buf[n] = 0;		close(fd);		st = strstr(buf, "proto=rsa");		if (st == nil)			goto initdss;		end = st;		for (; st > buf && *st != '\n'; --st) ;		for (; end < buf+4096 && *end != '\n'; ++end) ;	}	else {		strncpy(buf, p, 4095);		remove("/env/rsakey");	}	p = strstr(st, " n=");	if (p == nil || p > end) {		fprint(2, "No key (n) found\n");		free(buf);		return;	}	myrsakey.pub.n = strtomp(p+3, nil, 16, nil);	if (debug > 1)		fprint(2, "n=%M\n", myrsakey.pub.n);	p = strstr(st, " ek=");	if (p == nil || p > end) {		fprint(2, "No key (ek) found\n");		free(buf);		return;	}	pkas[k++] = &rsa_pka;	pkas[k] = nil;	myrsakey.pub.ek = strtomp(p+4, nil, 16, nil);	if (debug > 1)		fprint(2, "ek=%M\n", myrsakey.pub.ek);	p = strstr(st, " !dk=");	if (p == nil) {		p = strstr(st, "!dk?");		if (p == nil || p > end) {			// fprint(2, "No key (dk) found\n");			free(buf);			return;		}		else			goto initdss;	}	myrsakey.dk = strtomp(p+5, nil, 16, nil);	if (debug > 1)		fprint(2, "dk=%M\n", myrsakey.dk); initdss:	p = getenv("dsskey");	if (p == nil) {		fd = open("dsskey", OREAD);		if (fd < 0) {			fd = open("/mnt/factotum/ctl", OREAD);			if (fd < 0)				goto initdss;		}		n = read(fd, buf, 4095);		buf[n] = 0;		close(fd);		st = strstr(buf, "proto=dsa");		if (st == nil) {			free(buf);			return;		}		end = st;		for (; st > buf && *st != '\n'; --st) ;		for (; end < buf+4096 && *end != '\n'; ++end) ;	}	else {		strncpy(buf, p, 4095);		remove("/env/dsskey");	}	p = strstr(buf, " p=");	if (p == nil || p > end) {		fprint(2, "No key (p) found\n");		free(buf);		return;	}	mydsskey.pub.p = strtomp(p+3, nil, 16, nil);	p = strstr(buf, " q=");	if (p == nil || p > end) {		fprint(2, "No key (q) found\n");		free(buf);		return;	}	mydsskey.pub.q = strtomp(p+3, nil, 16, nil);	p = strstr(buf, " alpha=");	if (p == nil || p > end) {		fprint(2, "No key (g) found\n");		free(buf);		return;	}	mydsskey.pub.alpha = strtomp(p+7, nil, 16, nil);	p = strstr(buf, " key=");	if (p == nil || p > end) {		fprint(2, "No key (y) found\n");		free(buf);		return;	}	mydsskey.pub.key = strtomp(p+5, nil, 16, nil);	pkas[k++] = &dss_pka;	pkas[k] = nil;	p = strstr(buf, " !secret=");	if (p == nil) {		p = strstr(buf, "!secret?");		if (p == nil || p > end)			fprint(2, "No key (x) found\n");		free(buf);		return;	}	mydsskey.secret = strtomp(p+9, nil, 16, nil);	free(buf);} static Packet *rsa_ks(Conn *c){	Packet *ks; 	if (myrsakey.pub.ek == nil || myrsakey.pub.n == nil) {		fprint(2, "No public RSA key info\n");		return nil;	}	ks = new_packet(c);	add_string(ks, "ssh-rsa");	add_mp(ks, myrsakey.pub.ek);	add_mp(ks, myrsakey.pub.n);	return ks;} static voidesma_encode(uchar *h, uchar *em, int nb){	int n, i;	uchar hh[SHA1dlen];	static uchar sha1der[] = {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,		0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14}; 	sha1(h, SHA1dlen, hh, nil);	n = nb - (15 + SHA1dlen) - 3;	i = 0;	em[i++] = 0;	em[i++] = 1;	memset(em + i, 0xff, n);	i += n;	em[i++] = 0;	memmove(em + i, sha1der, sizeof(sha1der));	i += sizeof(sha1der);	memmove(em + i, hh, SHA1dlen);} static Packet *rsa_sign(Conn *c, uchar *m, int nm){	AuthRpc *ar;	Packet *sig;	mpint *s, *mm;	int fd, n, nbit;	uchar hh[SHA1dlen];	uchar *sstr, *em; 	if (myrsakey.dk) {		nbit = mpsignif (myrsakey.pub.n);		n = (nbit + 7) / 8;		sstr = emalloc9p(n);		em = emalloc9p(n);		/* Compute s: RFC 3447 */		esma_encode(m, em, n);		mm = betomp(em, n, nil);		s = mpnew(nbit);		mpexp(mm, myrsakey.dk, myrsakey.pub.n, s);		mptobe(s, sstr, n, nil);		mpfree(mm);		mpfree(s);		free(em);	}	else {		fd = open("/mnt/factotum/rpc", ORDWR);		if (fd < 0)			return nil;		sha1(m, nm, hh, nil);		ar = auth_allocrpc(fd);		if (ar == nil || auth_rpc(ar, "start", "role=sign proto=rsa", 19) != ARok				|| auth_rpc(ar, "write", hh, SHA1dlen) != ARok				|| auth_rpc(ar, "read", nil, 0) != ARok) {			if (debug)				fprint(2, "got error in factotum: %r\n");			auth_freerpc(ar);			close(fd);			return nil;		}		close(fd);		if (ar->arg == nil)			return nil;		sstr = emalloc9p(ar->narg);		memmove(sstr, ar->arg, ar->narg);		n = ar->narg;		auth_freerpc(ar);	}	sig = new_packet(c);	add_string(sig, pkas[c->pkalg]->name);	add_block(sig, sstr, n);	free(sstr);	return sig;} /* * 0 - If factotum failed, e.g. no key * 1 - If key is verified * -1 - If factotum found a key, but the verification fails */static intrsa_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int){	AuthRpc *ar;//	mpint *s, *mm;	char *p;	int fd, n, retval;//	int nbit;	uchar hh[SHA1dlen];//	uchar *sstr, *em;	char *sigblob;	char *buf; 	sigblob = emalloc9p(512);	buf = emalloc9p(256);	if (debug)		fprint(2, "In rsa_verify for connection: %d\n", c->id);#ifdef UNDEF	if (rsa_exponent) {		nbit = mpsignif (host_modulus);		n = (nbit + 7) / 8;		em = emalloc9p(n);		/* Compute s: RFC 3447 */		esma_encode(m, em, n);		mm = betomp(em, n, nil);		s = mpnew(1024);		mpexp(mm, rsa_exponent, host_modulus, s);		sstr = emalloc9p(n);		mptobe(s, sstr, n, nil);		free(em);		mpfree(mm);		mpfree(s);		retval = memcmp(sig, sstr, n);		free(sstr);		free(sigblob);		free(buf);		if (retval == 0)			return 1;		return 0;	}	else {#endif		retval = 1;		fd = open("/mnt/factotum/rpc", ORDWR);		if (fd < 0) {			if (debug)				fprint(2, "Could not open factotum RPC: %r\n");			free(sigblob);			free(buf);			return 0;		}		p = (char *)get_string(nil, (uchar *)sig, buf, 256, nil);		get_string(nil, (uchar *)p, sigblob, 512, &n);		sha1(m, nm, hh, nil);		if (user != nil)			p = smprint("role=verify proto=rsa user=%s", user);		else			p = smprint("role=verify proto=rsa sys=%s", c->remote);		ar = auth_allocrpc(fd);		if (ar == nil || auth_rpc(ar, "start", p, strlen(p)) != ARok				|| auth_rpc(ar, "write", hh, SHA1dlen) != ARok				|| auth_rpc(ar, "write", sigblob, n) != ARok				|| auth_rpc(ar, "read", nil, 0) != ARok) {			if (debug)				fprint(2, "got error in factotum: %r\n");			auth_freerpc(ar);			free(p);			close(fd);			free(sigblob);			free(buf);			return 0;		}		if (debug)			fprint(2, "Factotum returned %s\n", ar->ibuf);		if (strstr(ar->ibuf, "does not verify"))			retval = -1;		if (ar != nil)			auth_freerpc(ar);		free(p);		close(fd);		free(sigblob);		free(buf);		return retval;#ifdef UNDEF	}#endif} static Packet *dss_ks(Conn *c){	Packet *ks; 	if (mydsskey.pub.p == nil)		return nil;	ks = new_packet(c);	add_string(ks, "ssh-dss");	add_mp(ks, mydsskey.pub.p);	add_mp(ks, mydsskey.pub.q);	add_mp(ks, mydsskey.pub.alpha);	add_mp(ks, mydsskey.pub.key);	return ks;} static Packet *dss_sign(Conn *c, uchar *m, int nm){	AuthRpc *ar;	DSAsig *s;	Packet *sig;	mpint *mm;	int fd;	uchar sstr[2*SHA1dlen]; 	sha1(m, nm, sstr, nil);	sig = new_packet(c);	add_string(sig, pkas[c->pkalg]->name);	if (mydsskey.secret) {		mm = betomp(sstr, SHA1dlen, nil);		s = dsasign(&mydsskey, mm);		mptobe(s->r, sstr, SHA1dlen, nil);		mptobe(s->s, sstr+SHA1dlen, SHA1dlen, nil);		dsasigfree(s);		mpfree(mm);	}	else {		fd = open("/mnt/factotum/rpc", ORDWR);		if (fd < 0)			return nil;		ar = auth_allocrpc(fd);		if (ar == nil || auth_rpc(ar, "start", "role=sign proto=dsa", 19) != ARok				|| auth_rpc(ar, "write", sstr, SHA1dlen) != ARok				|| auth_rpc(ar, "read", nil, 0) != ARok) {			if (debug)				fprint(2, "got error in factotum: %r\n");			auth_freerpc(ar);			close(fd);			return nil;		}		close(fd);		memmove(sstr, ar->arg, ar->narg);		auth_freerpc(ar);	}	add_block(sig, sstr, 2*SHA1dlen);	return sig;} static intdss_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int nsig){	if (debug)		fprint(2, "In dss_verify for connection: %d\n", c->id);	USED(c);	USED(m);	USED(nm);	USED(user);	USED(sig);	USED(nsig); 	fprint(2, "DSS verify not supported yet, sorry\n");	return 0;} static intdh_server1(Conn *c, Packet *pack1){	return dh_server(c, pack1, p1, 1024);} static intdh_server14(Conn *c, Packet *pack1){	return dh_server(c, pack1, p14, 2048);} static intdh_server(Conn *c, Packet *pack1, mpint *grp, int nbit){	Packet *pack2, *ks, *sig;	mpint *y, *e, *f, *k;	int n;	uchar h[SHA1dlen]; 	qlock(&c->l);	f = mpnew(nbit);	k = mpnew(nbit);	/* Compute f: RFC4253 */	y = mprand(nbit / 8, genrandom, nil);	if (debug > 1)		fprint(2, "y=%M\n", y);	mpexp(two, y, grp, f);	if (debug > 1)		fprint(2, "f=%M\n", f);	/* Compute k: RFC4253 */	if (debug > 1)		dump_packet(pack1);	e = get_mp(pack1->payload+1);	if (debug > 1)		fprint(2, "e=%M\n", e);	mpexp(e, y, grp, k);	if (debug > 1)		fprint(2, "k=%M\n", k);	/* Compute H: RFC 4253 */	pack2 = new_packet(c);	if (debug)		fprint(2, "ID strings: %s---%s\n", c->otherid, MYID);	add_string(pack2, c->otherid);	add_string(pack2, MYID);	if (debug > 1) {		fprint(2, "received kexinit:");		dump_packet(c->rkexinit);		fprint(2, "\nsent kexinit:");		dump_packet(c->skexinit);

Lines 1–500 of 917.