aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/auth/factotum
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/auth/factotum')
-rw-r--r--src/cmd/auth/factotum/ctl.c5
-rw-r--r--src/cmd/auth/factotum/dat.h6
-rw-r--r--src/cmd/auth/factotum/dsa.c14
-rw-r--r--src/cmd/auth/factotum/fs.c2
-rw-r--r--src/cmd/auth/factotum/pkcs1.c57
-rw-r--r--src/cmd/auth/factotum/rpc.c35
-rw-r--r--src/cmd/auth/factotum/rsa.c148
7 files changed, 216 insertions, 51 deletions
diff --git a/src/cmd/auth/factotum/ctl.c b/src/cmd/auth/factotum/ctl.c
index df44b97d..85fbe5d8 100644
--- a/src/cmd/auth/factotum/ctl.c
+++ b/src/cmd/auth/factotum/ctl.c
@@ -40,6 +40,9 @@ ctlwrite(char *a)
Key *k;
Proto *proto;
+ while(*a == ' ' || *a == '\t' || *a == '\n')
+ a++;
+
if(a[0] == '#' || a[0] == '\0')
return 0;
@@ -63,7 +66,7 @@ ctlwrite(char *a)
*p++ = '\0';
switch(classify(a)){
default:
- werrstr("unknown verb");
+ werrstr("unknown verb %s", a);
return -1;
case 0: /* key */
attr = parseattr(p);
diff --git a/src/cmd/auth/factotum/dat.h b/src/cmd/auth/factotum/dat.h
index 11648328..678594a2 100644
--- a/src/cmd/auth/factotum/dat.h
+++ b/src/cmd/auth/factotum/dat.h
@@ -9,6 +9,8 @@ enum
RpcRead,
RpcStart,
RpcWrite,
+ RpcReadHex,
+ RpcWriteHex,
/* thread stack size - big buffers for printing */
STACK = 65536,
@@ -27,6 +29,7 @@ struct Rpc
int op;
void *data;
int count;
+ int hex; /* should result of read be turned into hex? */
};
struct Conv
@@ -214,9 +217,10 @@ extern int xiowrite(int, void*, int);
extern int xioasrdresp(int, void*, int);
extern int xioasgetticket(int, char*, char*);
-/* pkcs1.c */
+/* pkcs1.c - maybe should be in libsec */
typedef DigestState *DigestAlg(uchar*, ulong, uchar*, DigestState*);
int rsasign(RSApriv*, DigestAlg*, uchar*, uint, uchar*, uint);
+int rsaverify(RSApub*, DigestAlg*, uchar*, uint, uchar*, uint);
void mptoberjust(mpint*, uchar*, uint);
diff --git a/src/cmd/auth/factotum/dsa.c b/src/cmd/auth/factotum/dsa.c
index 73f8d296..c0d199e4 100644
--- a/src/cmd/auth/factotum/dsa.c
+++ b/src/cmd/auth/factotum/dsa.c
@@ -23,7 +23,7 @@ xdsasign(Conv *c)
{
int n;
mpint *m;
- uchar digest[SHA1dlen];
+ uchar digest[SHA1dlen], sigblob[20+20];
DSAsig *sig;
Key *k;
@@ -46,7 +46,13 @@ xdsasign(Conv *c)
mpfree(m);
if(sig == nil)
return -1;
- convprint(c, "%B %B", sig->r, sig->s);
+ if(mpsignif(sig->r) > 20*8 || mpsignif(sig->s) > 20*8){
+ werrstr("signature too long");
+ return -1;
+ }
+ mptoberjust(sig->r, sigblob, 20);
+ mptoberjust(sig->s, sigblob+20, 20);
+ convwrite(c, sigblob, sizeof sigblob);
dsasigfree(sig);
return 0;
}
@@ -80,11 +86,11 @@ readdsapriv(Key *k)
|| (priv->pub.q=strtomp(a, nil, 16, nil))==nil)
goto Error;
strlwr(a);
- if((a=strfindattr(k->privattr, "alpha"))==nil
+ if((a=strfindattr(k->attr, "alpha"))==nil
|| (priv->pub.alpha=strtomp(a, nil, 16, nil))==nil)
goto Error;
strlwr(a);
- if((a=strfindattr(k->privattr, "key"))==nil
+ if((a=strfindattr(k->attr, "key"))==nil
|| (priv->pub.key=strtomp(a, nil, 16, nil))==nil)
goto Error;
strlwr(a);
diff --git a/src/cmd/auth/factotum/fs.c b/src/cmd/auth/factotum/fs.c
index f9ad785b..88bbfd8b 100644
--- a/src/cmd/auth/factotum/fs.c
+++ b/src/cmd/auth/factotum/fs.c
@@ -166,7 +166,7 @@ static int
keylist(int i, char *a, uint nn)
{
int n;
- char buf[512];
+ char buf[4096];
Key *k;
if(i >= ring.nkey)
diff --git a/src/cmd/auth/factotum/pkcs1.c b/src/cmd/auth/factotum/pkcs1.c
index fb35ce83..f3278454 100644
--- a/src/cmd/auth/factotum/pkcs1.c
+++ b/src/cmd/auth/factotum/pkcs1.c
@@ -36,7 +36,7 @@ rsasign(RSApriv *key, DigestAlg *hash, uchar *digest, uint dlen,
/*
* Create number to sign.
*/
- len = (mpsignif(key->pub.n)+7)/8;
+ len = (mpsignif(key->pub.n)+7)/8 - 1;
if(len < n+2){
werrstr("rsa key too short");
return -1;
@@ -65,9 +65,41 @@ rsasign(RSApriv *key, DigestAlg *hash, uchar *digest, uint dlen,
mpfree(m);
if(s == nil)
return -1;
- mptoberjust(s, sig, len);
+ mptoberjust(s, sig, len+1);
mpfree(s);
- return len;
+ return len+1;
+}
+
+int
+rsaverify(RSApub *key, DigestAlg *hash, uchar *digest, uint dlen,
+ uchar *sig, uint siglen)
+{
+ uchar asn1[64], xasn1[64];
+ int n, nn;
+ mpint *m, *s;
+
+ /*
+ * Create ASN.1
+ */
+ n = mkasn1(asn1, hash, digest, dlen);
+
+ /*
+ * Extract plaintext of signature.
+ */
+ s = betomp(sig, siglen, nil);
+ if(s == nil)
+ return -1;
+ m = rsaencrypt(key, s, nil);
+ mpfree(s);
+ if(m == nil)
+ return -1;
+ nn = mptobe(m, xasn1, sizeof xasn1, nil);
+ mpfree(m);
+ if(n != nn || memcmp(asn1, xasn1, n) != 0){
+ werrstr("signature did not verify");
+ return -1;
+ }
+ return 0;
}
/*
@@ -116,6 +148,15 @@ uchar oidmd5[] = { O0(1, 2), O2(840), O3(113549), 2, 5 };
* digestAlgorithm AlgorithmIdentifier,
* digest OCTET STRING
* }
+ *
+ * except that OpenSSL seems to sign
+ *
+ * DigestInfo ::= SEQUENCE {
+ * SEQUENCE{ digestAlgorithm AlgorithmIdentifier, NULL }
+ * digest OCTET STRING
+ * }
+ *
+ * instead. Sigh.
*/
static int
mkasn1(uchar *asn1, DigestAlg *alg, uchar *d, uint dlen)
@@ -138,17 +179,25 @@ mkasn1(uchar *asn1, DigestAlg *alg, uchar *d, uint dlen)
*p++ = 0x30; /* sequence */
p++;
+ *p++ = 0x30; /* another sequence */
+ p++;
+
*p++ = 0x06; /* object id */
*p++ = olen;
memmove(p, obj, olen);
p += olen;
+ *p++ = 0x05; /* null */
+ *p++ = 0;
+
+ asn1[3] = p - (asn1+4); /* end of inner sequence */
+
*p++ = 0x04; /* octet string */
*p++ = dlen;
memmove(p, d, dlen);
p += dlen;
- asn1[1] = p - (asn1+2);
+ asn1[1] = p - (asn1+2); /* end of outer sequence */
return p-asn1;
}
diff --git a/src/cmd/auth/factotum/rpc.c b/src/cmd/auth/factotum/rpc.c
index e9c163aa..8e2b17a0 100644
--- a/src/cmd/auth/factotum/rpc.c
+++ b/src/cmd/auth/factotum/rpc.c
@@ -40,6 +40,8 @@ char *rpcname[] =
"read",
"start",
"write",
+ "readhex",
+ "writehex",
};
static int
@@ -153,7 +155,20 @@ rpcexec(Conv *c)
{
uchar *p;
+ c->rpc.hex = 0;
switch(c->rpc.op){
+ case RpcWriteHex:
+ c->rpc.op = RpcWrite;
+ if(dec16(c->rpc.data, c->rpc.count, c->rpc.data, c->rpc.count) != c->rpc.count/2){
+ rpcrespond(c, "bad hex");
+ break;
+ }
+ c->rpc.count /= 2;
+ goto Default;
+ case RpcReadHex:
+ c->rpc.hex = 1;
+ c->rpc.op = RpcRead;
+ /* fall through */
case RpcRead:
if(c->rpc.count > 0){
rpcrespond(c, "error read takes no parameters");
@@ -161,6 +176,7 @@ rpcexec(Conv *c)
}
/* fall through */
default:
+ Default:
if(!c->active){
if(c->done)
rpcrespond(c, "done");
@@ -224,11 +240,18 @@ void
rpcrespondn(Conv *c, char *verb, void *data, int count)
{
char *p;
+ int need, hex;
if(c->hangup)
return;
- if(strlen(verb)+1+count > sizeof c->reply){
+ need = strlen(verb)+1+count;
+ hex = 0;
+ if(c->rpc.hex && strcmp(verb, "ok") == 0){
+ need += count;
+ hex = 1;
+ }
+ if(need > sizeof c->reply){
print("RPC response too large; caller %#lux", getcallerpc(&c));
return;
}
@@ -236,8 +259,14 @@ rpcrespondn(Conv *c, char *verb, void *data, int count)
strcpy(c->reply, verb);
p = c->reply + strlen(c->reply);
*p++ = ' ';
- memmove(p, data, count);
- c->nreply = count + (p - c->reply);
+ if(hex){
+ enc16(p, 2*count, data, count);
+ p += 2*count;
+ }else{
+ memmove(p, data, count);
+ p += count;
+ }
+ c->nreply = p - c->reply;
(*c->kickreply)(c);
c->rpc.op = RpcUnknown;
}
diff --git a/src/cmd/auth/factotum/rsa.c b/src/cmd/auth/factotum/rsa.c
index 327dbc5b..34ddb784 100644
--- a/src/cmd/auth/factotum/rsa.c
+++ b/src/cmd/auth/factotum/rsa.c
@@ -4,65 +4,116 @@
/*
* RSA authentication.
*
- * Client:
+ * Encrypt/Decrypt:
* start n=xxx ek=xxx
* write msg
- * read decrypt(msg)
+ * read encrypt/decrypt(msg)
*
* Sign (PKCS #1 using hash=sha1 or hash=md5)
* 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
+ *
* all numbers are hexadecimal biginits parsable with strtomp.
* must be lower case for attribute matching in start.
*/
static int
-rsaclient(Conv *c)
+xrsadecrypt(Conv *c)
{
- char *chal;
- mpint *m;
+ char *txt, buf[4096], *role;
+ int n, ret;
+ mpint *m, *mm;
Key *k;
+ RSApriv *key;
+
+ ret = -1;
+ txt = nil;
+ m = nil;
+ mm = nil;
+ /* fetch key */
+ c->state = "keylookup";
k = keylookup("%A", c->attr);
if(k == nil)
- return -1;
- c->state = "read challenge";
- if(convreadm(c, &chal) < 0){
- keyclose(k);
- return -1;
+ goto out;
+ key = k->priv;
+
+ /* make sure have private half if needed */
+ role = strfindattr(c->attr, "role");
+ if(strcmp(role, "decrypt") == 0 && !key->c2){
+ werrstr("missing private half of key -- cannot decrypt");
+ goto out;
}
- if(strlen(chal) < 32){
- badchal:
- free(chal);
- convprint(c, "bad challenge");
- keyclose(k);
- return -1;
+
+ /* read text */
+ c->state = "read";
+ if((n=convreadm(c, &txt)) < 0)
+ goto out;
+ if(n < 32){
+ convprint(c, "data too short");
+ goto out;
}
- m = strtomp(chal, nil, 16, nil);
+
+ /* encrypt/decrypt */
+ m = betomp(txt, n, nil);
if(m == nil)
- goto badchal;
- free(chal);
- m = rsadecrypt(k->priv, m, m);
- convprint(c, "%B", m);
+ goto out;
+ if(strcmp(role, "decrypt") == 0)
+ mm = rsadecrypt(key, m, m);
+ else
+ mm = rsaencrypt(&key->pub, m, nil);
+ if(mm == nil)
+ goto out;
+ n = mptobe(m, buf, sizeof buf, nil);
+
+ /* send response */
+ c->state = "write";
+ convwrite(c, buf, n);
+ ret = 0;
+
+out:
mpfree(m);
+ mpfree(mm);
keyclose(k);
- return 0;
+ free(txt);
+ return ret;
}
static int
xrsasign(Conv *c)
{
- char *hash;
- int dlen, n;
+ char *hash, *role;
+ int dlen, n, ret;
DigestAlg *hashfn;
Key *k;
+ RSApriv *key;
uchar sig[1024], digest[64];
+ char *sig2;
+ ret = -1;
+
+ /* fetch key */
+ c->state = "keylookup";
k = keylookup("%A", c->attr);
if(k == nil)
- return -1;
+ goto out;
+
+ /* make sure have private half if needed */
+ key = k->priv;
+ role = strfindattr(c->attr, "role");
+ if(strcmp(role, "sign") == 0 && !key->c2){
+ werrstr("missing private half of key -- cannot sign");
+ goto out;
+ }
+
+ /* get hash type from key */
hash = strfindattr(k->attr, "hash");
if(hash == nil)
hash = "sha1";
@@ -74,20 +125,38 @@ xrsasign(Conv *c)
dlen = MD5dlen;
}else{
werrstr("unknown hash function %s", hash);
- return -1;
+ goto out;
}
- c->state = "read data";
- if((n=convread(c, digest, dlen)) < 0){
- keyclose(k);
- return -1;
+
+ /* read hash */
+ c->state = "read hash";
+ if((n=convread(c, digest, dlen)) < 0)
+ goto out;
+
+ if(strcmp(role, "sign") == 0){
+ /* sign */
+ if((n=rsasign(key, hashfn, digest, dlen, sig, sizeof sig)) < 0)
+ goto out;
+
+ /* write */
+ convwrite(c, sig, n);
+ }else{
+ /* read signature */
+ if((n = convreadm(c, &sig2)) < 0)
+ goto out;
+
+ /* verify */
+ if(rsaverify(&key->pub, hashfn, digest, dlen, (uchar*)sig2, n) == 0)
+ convprint(c, "ok");
+ else
+ convprint(c, "signature does not verify");
+ free(sig2);
}
- memset(sig, 0xAA, sizeof sig);
- n = rsasign(k->priv, hashfn, digest, dlen, sig, sizeof sig);
+ ret = 0;
+
+out:
keyclose(k);
- if(n < 0)
- return -1;
- convwrite(c, sig, n);
- return 0;
+ return ret;
}
/*
@@ -119,6 +188,9 @@ readrsapriv(Key *k)
|| (priv->pub.n=strtomp(a, nil, 16, nil))==nil)
goto Error;
strlwr(a);
+ if(k->privattr == nil) /* only public half */
+ return priv;
+
if((a=strfindattr(k->privattr, "!p"))==nil
|| (priv->p=strtomp(a, nil, 16, nil))==nil)
goto Error;
@@ -177,8 +249,10 @@ rsaclose(Key *k)
static Role
rsaroles[] =
{
- "client", rsaclient,
"sign", xrsasign,
+ "verify", xrsasign, /* public operation */
+ "decrypt", xrsadecrypt,
+ "encrypt", xrsadecrypt, /* public operation */
0
};