Plan 9 from Bell Labs’s /usr/web/sources/contrib/miller/factotum/dsa.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 * DSA authentication.
 * 
 * Sign
 *	start n=xxx ek=xxx
 *	write hash(msg)
 *	read signature(hash(msg))
 * 
 * Verify:
 *	start n=xxx ek=xxx
 *	write hash(msg)
 *	write signature(hash(msg))
 *	read ok or fail
 *
 */

#include "dat.h"

enum {
	VNeedHash,
	VNeedSig,
	VHaveResp,
	SNeedHash,
	SHaveResp,
	Maxphase,

	DSAdlen = 20,
	DSAsiglen = DSAdlen*2,
};

static char *phasenames[] = {
[VNeedHash]	"VNeedHash",
[VNeedSig]	"VNeedSig",
[VHaveResp]	"VHaveResp",
[SNeedHash]	"SNeedHash",
[SHaveResp]	"SHaveResp",
};

struct State
{
	DSApriv *priv;
	mpint *resp;
	int off;
	Key *key;
	mpint *digest;
	int sigresp;
};

static DSApriv*
readdsapriv(Key *k)
{
	char *a;
	DSApriv *priv;

	priv = dsaprivalloc();

	if((a=_strfindattr(k->attr, "p"))==nil 
	|| (priv->pub.p=strtomp(a, nil, 16, nil))==nil)
		goto Error;
	if((a=_strfindattr(k->attr, "q"))==nil 
	|| (priv->pub.q=strtomp(a, nil, 16, nil))==nil)
		goto Error;
	if((a=_strfindattr(k->attr, "alpha"))==nil 
	|| (priv->pub.alpha=strtomp(a, nil, 16, nil))==nil)
		goto Error;
	if((a=_strfindattr(k->attr, "key"))==nil 
	|| (priv->pub.key=strtomp(a, nil, 16, nil))==nil)
		goto Error;
	if(k->privattr == nil)	/* only public half */
		return priv;
	if((a=_strfindattr(k->privattr, "!secret"))==nil 
	|| (priv->secret=strtomp(a, nil, 16, nil))==nil)
		goto Error;
	return priv;

Error:
	dsaprivfree(priv);
	return nil;
}

/*
 * Mptobe but shift right to fill buffer.
 */
static void
mptoberjust(mpint *b, uchar *buf, uint len)
{
	int n;

	n = mptobe(b, buf, len, nil);
	assert(n >= 0);
	if(n < len){
		len -= n;
		memmove(buf+len, buf, n);
		memset(buf, 0, len);
	}
}

static int
dsainit(Proto*, Fsstate *fss)
{
	Keyinfo ki;
	State *s;
	char *role;

	if((role = _strfindattr(fss->attr, "role")) == nil)
		return failure(fss, "dsa role not specified");
	if(strcmp(role, "sign") == 0)
		fss->phase = SNeedHash;
	else if(strcmp(role, "verify") == 0)
		fss->phase = VNeedHash;
	else
		return failure(fss, "dsa role %s unimplemented", role);

	s = emalloc(sizeof *s);
	fss->phasename = phasenames;
	fss->maxphase = Maxphase;
	fss->ps = s;

	switch(fss->phase){
	case SNeedHash:
	case VNeedHash:
		mkkeyinfo(&ki, fss, nil);
		if(findkey(&s->key, &ki, nil) != RpcOk)
			return failure(fss, nil);
		/* signing needs private key */
		if(fss->phase == SNeedHash && s->key->privattr == nil)
			return failure(fss, "missing private half of key -- cannot sign");
	}
	return RpcOk;
}

static int
dsaread(Fsstate *fss, void *va, uint *n)
{
	DSApriv *priv;
	DSAsig *sig;
	State *s;

	s = fss->ps;
	switch(fss->phase){
	default:
		return phaseerror(fss, "read");
	case SHaveResp:
		if(*n < DSAsiglen)
			failure(fss, "signature buffer too short");
		priv = s->key->priv;
		sig = dsasign(priv, s->digest);
		assert(sig != nil);
		if(mpsignif(sig->r) > DSAdlen*8 || mpsignif(sig->s) > DSAdlen*8){
			dsasigfree(sig);
			failure(fss, "signature too long");
		}
		mptoberjust(sig->r, (uchar*)va, DSAdlen);
		mptoberjust(sig->s, (uchar*)va+DSAdlen, DSAdlen);
		dsasigfree(sig);
		*n = DSAsiglen;
		fss->phase = Established;
		return RpcOk;
	case VHaveResp:
		*n = snprint(va, *n, "%s", s->sigresp == 0? "ok" : "signature does not verify");
		fss->phase = Established;
		return RpcOk;
	}
}

static int
dsawrite(Fsstate *fss, void *va, uint n)
{
	DSApriv *priv;
	DSAsig *sig;
	State *s;

	s = fss->ps;
	switch(fss->phase){
	default:
		return phaseerror(fss, "write");
	case SNeedHash:
	case VNeedHash:
		if(n != SHA1dlen)
			return failure(fss, "digest length %d should be %d", n, SHA1dlen);
		s->digest = betomp((uchar*)va, SHA1dlen, nil);
		assert(s->digest != nil);
		if(fss->phase == VNeedHash)
			fss->phase = VNeedSig;
		else
			fss->phase = SHaveResp;
		return RpcOk;
	case VNeedSig:
		if(n != DSAsiglen)
			return failure(fss, "signature length %d should be %d", n, DSAsiglen);
		sig = dsasigalloc();
		sig->r = betomp((uchar*)va, DSAdlen, nil);
		sig->s = betomp((uchar*)va+DSAdlen, DSAdlen, nil);
		priv = s->key->priv;
		s->sigresp = dsaverify(&priv->pub, sig, s->digest);
		dsasigfree(sig);
		fss->phase = VHaveResp;
		return RpcOk;
	}
}

static void
dsaclose(Fsstate *fss)
{
	State *s;

	s = fss->ps;
	if(s->key)
		closekey(s->key);
	if(s->resp)
		mpfree(s->resp);
	if(s->digest)
		mpfree(s->digest);
	free(s);
}

static int
dsaaddkey(Key *k, int before)
{
	fmtinstall('B', mpfmt);

	if((k->priv = readdsapriv(k)) == nil){
		werrstr("malformed key data");
		return -1;
	}
	return replacekey(k, before);
}

static void
dsaclosekey(Key *k)
{
	dsaprivfree(k->priv);
}

Proto dsa = {
.name=	"dsa",
.init=		dsainit,
.write=	dsawrite,
.read=	dsaread,
.close=	dsaclose,
.addkey=	dsaaddkey,
.closekey=	dsaclosekey,
};

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].