diff options
author | rsc <devnull@localhost> | 2005-02-13 18:04:00 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-02-13 18:04:00 +0000 |
commit | ce94dbe662155bd60d6839b5e8c82ad708667bcd (patch) | |
tree | 0c405ef046615640061cc6080b9fee516c5c80f8 /src/cmd/auth/factotum | |
parent | ea77b9ce7c579a2e625806dc01104d5f6929cc43 (diff) | |
download | plan9port-ce94dbe662155bd60d6839b5e8c82ad708667bcd.tar.gz plan9port-ce94dbe662155bd60d6839b5e8c82ad708667bcd.tar.bz2 plan9port-ce94dbe662155bd60d6839b5e8c82ad708667bcd.zip |
add ssh-agent via factotum
Diffstat (limited to 'src/cmd/auth/factotum')
-rw-r--r-- | src/cmd/auth/factotum/ctl.c | 5 | ||||
-rw-r--r-- | src/cmd/auth/factotum/dat.h | 6 | ||||
-rw-r--r-- | src/cmd/auth/factotum/dsa.c | 14 | ||||
-rw-r--r-- | src/cmd/auth/factotum/fs.c | 2 | ||||
-rw-r--r-- | src/cmd/auth/factotum/pkcs1.c | 57 | ||||
-rw-r--r-- | src/cmd/auth/factotum/rpc.c | 35 | ||||
-rw-r--r-- | src/cmd/auth/factotum/rsa.c | 148 |
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 }; |