957 lines · 21.8 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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 "netssh.h" #undef VERIFYKEYS		/* TODO until it's fixed */ enum {	Errnokey = -2,	/* no key on keyring */	Errnoverify,	/* factotum found a key, but verification failed */	Errfactotum,	/* factotum failure (e.g., no key) */	Errnone,	/* key verified */}; 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;int nokeyverify; static DSApriv mydsskey;static RSApriv myrsakey; voiddh_init(PKA *pkas[]){	char *buf, *p, *st, *end;	int fd, n, k; 	if(debug > 1)		sshdebug(nil, "dh_init");	k = 0;	pkas[k] = nil;	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) {		remove("/env/rsakey");		st = buf = p;		end = buf + strlen(p);	} else {		/*		 * it would be better to use bio and rdline here instead of		 * reading all of factotum's contents into memory at once.		 */		buf = emalloc9p(Maxfactotum);		fd = open("rsakey", OREAD);		if (fd < 0 && (fd = open("/mnt/factotum/ctl", OREAD)) < 0)			goto norsa;		n = readn(fd, buf, Maxfactotum - 1);		buf[n >= 0? n: 0] = 0;		close(fd);		assert(n < Maxfactotum - 1); 		st = strstr(buf, "proto=rsa");		if (st == nil) {			sshlog(nil, "no proto=rsa key in factotum");			goto norsa;		}		end = st;		for (; st > buf && *st != '\n'; --st)			;		for (; end < buf + Maxfactotum && *end != '\n'; ++end)			;	}	p = strstr(st, " n=");	if (p == nil || p > end) {		sshlog(nil, "no key (n) found");		free(buf);		return;	}	myrsakey.pub.n = strtomp(p+3, nil, 16, nil);	if (debug > 1)		sshdebug(nil, "n=%M", myrsakey.pub.n);	p = strstr(st, " ek=");	if (p == nil || p > end) {		sshlog(nil, "no key (ek) found");		free(buf);		return;	}	pkas[k++] = &rsa_pka;	pkas[k] = nil;	myrsakey.pub.ek = strtomp(p+4, nil, 16, nil);	if (debug > 1)		sshdebug(nil, "ek=%M", myrsakey.pub.ek);	p = strstr(st, " !dk=");	if (p == nil) {		p = strstr(st, "!dk?");		if (p == nil || p > end) {			// sshlog(nil, "no key (dk) found");			free(buf);			return;		}		goto norsa;	}	myrsakey.dk = strtomp(p+5, nil, 16, nil);	if (debug > 1)		sshdebug(nil, "dk=%M", myrsakey.dk);norsa:	free(buf); 	p = getenv("dsskey");	if (p != nil) {		remove("/env/dsskey");		buf = p;		end = buf + strlen(p);	} else {		/*		 * it would be better to use bio and rdline here instead of		 * reading all of factotum's contents into memory at once.		 */		buf = emalloc9p(Maxfactotum);		fd = open("dsskey", OREAD);		if (fd < 0 && (fd = open("/mnt/factotum/ctl", OREAD)) < 0)			return;		n = readn(fd, buf, Maxfactotum - 1);		buf[n >= 0? n: 0] = 0;		close(fd);		assert(n < Maxfactotum - 1); 		st = strstr(buf, "proto=dsa");		if (st == nil) {			sshlog(nil, "no proto=dsa key in factotum");			free(buf);			return;		}		end = st;		for (; st > buf && *st != '\n'; --st)			;		for (; end < buf + Maxfactotum && *end != '\n'; ++end)			;	}	p = strstr(buf, " p=");	if (p == nil || p > end) {		sshlog(nil, "no key (p) found");		free(buf);		return;	}	mydsskey.pub.p = strtomp(p+3, nil, 16, nil);	p = strstr(buf, " q=");	if (p == nil || p > end) {		sshlog(nil, "no key (q) found");		free(buf);		return;	}	mydsskey.pub.q = strtomp(p+3, nil, 16, nil);	p = strstr(buf, " alpha=");	if (p == nil || p > end) {		sshlog(nil, "no key (g) found");		free(buf);		return;	}	mydsskey.pub.alpha = strtomp(p+7, nil, 16, nil);	p = strstr(buf, " key=");	if (p == nil || p > end) {		sshlog(nil, "no key (y) found");		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)			sshlog(nil, "no key (x) found");		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) {		sshlog(c, "no public RSA key info");		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 - (nelem(sha1der) + 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 ||		    ar->arg == nil) {			sshdebug(c, "got error in factotum: %r");			auth_freerpc(ar);			close(fd);			return nil;		}		sstr = emalloc9p(ar->narg);		memmove(sstr, ar->arg, ar->narg);		n = ar->narg; 		auth_freerpc(ar);		close(fd);	}	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){	int fd, n, retval, nbit;	char *buf, *p, *sigblob;	uchar *sstr, *em;	uchar hh[SHA1dlen];	mpint *s, *mm, *rsa_exponent, *host_modulus;	AuthRpc *ar; 	sshdebug(c, "in rsa_verify for connection: %d", c->id);	SET(rsa_exponent, host_modulus);	USED(rsa_exponent, host_modulus);	if (0 && 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);		retval = (retval == 0);	} else {		retval = 1;		fd = open("/mnt/factotum/rpc", ORDWR);		if (fd < 0) {			sshdebug(c, "could not open factotum RPC: %r");			return 0;		}		buf = emalloc9p(Blobsz / 2);		sigblob = emalloc9p(Blobsz);		p = (char *)get_string(nil, (uchar *)sig, buf, Blobsz / 2, nil);		get_string(nil, (uchar *)p, sigblob, Blobsz, &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) {			sshdebug(c, "got error in factotum: %r");			retval = 0;		} else {			sshdebug(c, "factotum returned %s", ar->ibuf);			if (strstr(ar->ibuf, "does not verify") != nil)				retval = -1;		}		if (ar != nil)			auth_freerpc(ar);		free(p);		close(fd);		free(sigblob);		free(buf);	}	return retval;} 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) {			sshdebug(c, "got error in factotum: %r");			auth_freerpc(ar);			close(fd);			return nil;		}		memmove(sstr, ar->arg, ar->narg);		auth_freerpc(ar);		close(fd);	}	add_block(sig, sstr, 2*SHA1dlen);	return sig;} static intdss_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int nsig){	sshdebug(c, "in dss_verify for connection: %d", c->id);	USED(m, nm, user, sig, nsig);	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, ret;	uchar h[SHA1dlen]; 	ret = -1;	qlock(&c->l);	f = mpnew(nbit);	k = mpnew(nbit); 	/* Compute f: RFC4253 */	y = mprand(nbit / 8, genrandom, nil);	if (debug > 1)		sshdebug(c, "y=%M", y);	mpexp(two, y, grp, f);	if (debug > 1)		sshdebug(c, "f=%M", f); 	/* Compute k: RFC4253 */	if (debug > 1)		dump_packet(pack1);	e = get_mp(pack1->payload+1);	if (debug > 1)		sshdebug(c, "e=%M", e);	mpexp(e, y, grp, k);	if (debug > 1)		sshdebug(c, "k=%M", k); 	/* Compute H: RFC 4253 */

Lines 1–500 of 957.