Charles.Forsyth20060303644188019 years agoHistory
446 lines · 7.4 KB · C
RawDownload
#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"../port/error.h" #include	"interp.h"#include	<isa.h>#include	"runt.h"#include	"mp.h"#include	"libsec.h"#include "../../libkeyring/keys.h" /* * experimental version of signed modules */ enum{	Qdir,	Qkey,	Qctl, 	Maxkey = 2048}; static Dirtab signdir[] ={	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,	"signerkey",	{Qkey},	0,			0644,	"signerctl",	{Qctl},	0,			0600,}; typedef struct Get Get;struct Get {	uchar*	p;	uchar*	ep;}; #define	G32(b)	((b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3]) static	int	vc(Get*);static	int	vs(void*, int, Get*, int);static Signerkey* findsignerkey(Skeyset*, char*, int, char*);extern vlong		osusectime(void); intverifysigner(uchar *sign, int len, uchar *data, ulong ndata){	Get sig;	int alg;	ulong issued, expires, now;	int footprint, r, n;	uchar buf[128], digest[SHA1dlen];	DigestState *ds;	volatile struct {BigInt b;} b;	volatile struct {BigInt s;} s;	SigAlgVec *sa;	Signerkey *key;	Skeyset *sigs; 	/* alg[1] issued[4] expires[4] footprint[2] signer[n] sig[m] */	sigs = up->env->sigs;	if(sigs == nil)		return 1;	/* not enforcing signed modules */	sig.p = sign;	sig.ep = sign+len;	alg = vc(&sig);	if(alg != 2)		return 0;	/* we do only SHA1/RSA */	sa = findsigalg("rsa");	if(sa == nil)		return 0;	if(vs(buf, sizeof(buf), &sig, 4) < 0)		return 0;	now = osusectime()/1000000;	issued = G32(buf);	if(vs(buf, sizeof(buf), &sig, 4) < 0)		return 0;	if(issued != 0 && now < issued)		return 0;	expires = G32(buf);	if(expires != 0 && now >= expires)		return 0;	footprint = vc(&sig) << 8;	footprint |= vc(&sig);	if(footprint < 0)		return 0;	r = 0;	b.b = nil;	s.s = nil;	qlock(sigs);	if(waserror())		goto out;	if((n = vs(buf, sizeof(buf)-NUMSIZE-1, &sig, -1)) < 0)	/* owner */		goto out;	buf[n] = 0;	key = findsignerkey(sigs, sa->name, footprint, (char*)buf);	if(key == nil)		goto out;	n += snprint((char*)buf+n, NUMSIZE, " %lud", expires);	ds = sha1(buf, n, nil, nil);	sha1(data, ndata, digest, ds);	b.b = betomp(digest, SHA1dlen, nil);	if(b.b == nil)		goto out;	s.s = betomp(sig.p, sig.ep-sig.p, nil);	if(s.s == nil)		goto out;	r = (*sa->verify)(b.b, s.s, key->pk);out:	qunlock(sigs);	if(b.b != nil)		mpfree(b.b);	if(s.s != nil)		mpfree(s.s);	return r;} intmustbesigned(char *path, uchar*, ulong, Dir *dir){	USED(path);if(0)print("load %s: %d %C\n", path, up->env->sigs!=nil, dir==nil?'?':dir->type);	/* allow only signed modules and those in #/; already loaded modules are reloaded from cache */	return up->env->sigs != nil && (dir == nil || dir->type != '/');} static intvc(Get *g){	return g->p < g->ep? *g->p++: -1;} static intvs(void *s, int lim, Get *g, int n){	int nr; 	if(n < 0){		if(g->p >= g->ep)			return -1;		n = *g->p++;		lim--;	}	if(n > lim)		return -1;	nr = g->ep - g->p;	if(n > nr)		return -1;	if(s != nil)		memmove(s, g->p, n);	g->p += n;	return n;} static char*cstring(char *str, char **strp){	char *p, *s;	int n; 	p = strchr(str, '\n');	if(p == 0)		p = str + strlen(str);	n = p - str;	s = malloc(n+1);	if(s == nil)		return nil;	memmove(s, str, n);	s[n] = 0; 	if(strp){		if(*p)			p++;		*strp = p;	} 	return s;} static SigAlgVec*cstrtoalg(char *str, char **strp){	int n;	char *p, name[KNAMELEN]; 	p = strchr(str, '\n');	if(p == 0){		p = str + strlen(str);		if(strp)			*strp = p;	} else {		if(strp)			*strp = p+1;	} 	n = p - str;	if(n >= sizeof(name))		return nil;	strncpy(name, str, n);	name[n] = 0;	return findsigalg(name);} static Signerkey*strtopk(char *buf){	SigAlgVec *sa;	char *p;	Signerkey *key; 	key = malloc(sizeof(*key));	if(key == nil)		return nil;	key->ref = 1;	sa = cstrtoalg(buf, &p);	if(sa == nil){		free(key);		return nil;	}	key->alg = sa;	key->pkfree = sa->pkfree;	key->owner = cstring(p, &p);	if(key->owner == nil){		free(key);		return nil;	}	key->pk = (*sa->str2pk)(p, &p);	if(key->pk == nil){		free(key->owner);		free(key);		return nil;	}	return key;} static Signerkey*findsignerkey(Skeyset *sigs, char *alg, int footprint, char *owner){	int i;	Signerkey *key; 	for(i=0; i<sigs->nkey; i++){		key = sigs->keys[i];		if(key->footprint == footprint &&		   strcmp(alg, ((SigAlgVec*)key->alg)->name) == 0 &&		   strcmp(key->owner, owner) == 0)			return key;	}	return nil;} static Chan*signattach(char *spec){	return devattach(L'Σ', spec);} static Walkqid*signwalk(Chan *c, Chan *nc, char **name, int nname){	return devwalk(c, nc, name, nname, signdir, nelem(signdir), devgen);} static intsignstat(Chan *c, uchar *db, int n){	return devstat(c, db, n, signdir, nelem(signdir), devgen);} static Chan*signopen(Chan *c, int omode){	if(c->qid.type & QTDIR) {		if(omode != OREAD)			error(Eisdir);		c->mode = openmode(omode);		c->flag |= COPEN;		c->offset = 0;		return c;	} 	switch((ulong)c->qid.path){	case Qctl:		if(!iseve())			error(Eperm);		break; 	case Qkey:		if(omode != OREAD && !iseve())			error(Eperm);		break;	} 	c->mode = openmode(omode);	c->flag |= COPEN;	c->offset = 0;	return c;} static voidsignclose(Chan *c){	USED(c);} static longsignread(Chan *c, void *va, long n, vlong offset){	char *buf, *p;	SigAlgVec *sa;	Skeyset *sigs;	Signerkey *key;	int i; 	if(c->qid.type & QTDIR)		return devdirread(c, va, n, signdir, nelem(signdir), devgen);	sigs = up->env->sigs;	if(sigs == nil)		return 0;	switch((ulong)c->qid.path){	case Qkey:		buf = smalloc(Maxkey);		if(waserror()){			free(buf);			nexterror();		}		qlock(sigs);		if(waserror()){			qunlock(sigs);			nexterror();		}		p = buf;		for(i=0; i<sigs->nkey; i++){			key = sigs->keys[i];			sa = key->alg;			p = seprint(p, buf+Maxkey, "owner=%s alg=%s footprint=%ud expires=%lud\n",				key->owner, sa->name, key->footprint, key->expires);		}		poperror();		qunlock(sigs);		n = readstr(offset, va, n, buf);		poperror();		free(buf);		return n; 	case Qctl:		return readnum(offset, va, n, sigs->nkey, NUMSIZE);	}	return 0;} static longsignwrite(Chan *c, void *va, long n, vlong offset){	char *buf;	Skeyset *sigs;	Signerkey *okey, *key;	int i; 	if(c->qid.type & QTDIR)		error(Eisdir);	USED(offset);	switch((ulong)c->qid.path){	case Qkey:		if(n >= Maxkey)			error(Etoobig);		buf = smalloc(Maxkey);		if(waserror()){			free(buf);			nexterror();		}		memmove(buf, va, n);		buf[n] = 0; 		key = strtopk(buf);		if(key == nil)			error("bad key syntax");		poperror();		free(buf); 		if(waserror()){			freeskey(key);			nexterror();		}		sigs = up->env->sigs;		if(sigs == nil){			sigs = malloc(sizeof(*sigs));			if(sigs == nil)				error(Enomem);			sigs->ref = 1;			up->env->sigs = sigs;		}		qlock(sigs);		if(waserror()){			qunlock(sigs);			nexterror();		}		for(i=0; i<sigs->nkey; i++){			okey = sigs->keys[i];			if(strcmp(okey->owner, key->owner) == 0){				/* replace existing key */				sigs->keys[i] = key;				freeskey(okey);				break;			}		}		if(i >= sigs->nkey){			if(sigs->nkey >= nelem(sigs->keys))				error("too many keys");			sigs->keys[sigs->nkey++] = key;		}		poperror();		qunlock(sigs);		poperror();	/* key */ 		return n;	case Qctl:		error(Ebadctl);		break;	}	return 0;} Dev signdevtab = {	L'Σ',	"sign", 	devreset,	devinit,	devshutdown,	signattach,	signwalk,	signstat,	signopen,	devcreate,	signclose,	signread,	devbread,	signwrite,	devbwrite,	devremove,	devwstat};