add ssh-agent via factotum

This commit is contained in:
rsc 2005-02-13 18:04:00 +00:00
parent ea77b9ce7c
commit ce94dbe662
9 changed files with 1267 additions and 59 deletions

View file

@ -40,6 +40,9 @@ ctlwrite(char *a)
Key *k; Key *k;
Proto *proto; Proto *proto;
while(*a == ' ' || *a == '\t' || *a == '\n')
a++;
if(a[0] == '#' || a[0] == '\0') if(a[0] == '#' || a[0] == '\0')
return 0; return 0;
@ -63,7 +66,7 @@ ctlwrite(char *a)
*p++ = '\0'; *p++ = '\0';
switch(classify(a)){ switch(classify(a)){
default: default:
werrstr("unknown verb"); werrstr("unknown verb %s", a);
return -1; return -1;
case 0: /* key */ case 0: /* key */
attr = parseattr(p); attr = parseattr(p);

View file

@ -9,6 +9,8 @@ enum
RpcRead, RpcRead,
RpcStart, RpcStart,
RpcWrite, RpcWrite,
RpcReadHex,
RpcWriteHex,
/* thread stack size - big buffers for printing */ /* thread stack size - big buffers for printing */
STACK = 65536, STACK = 65536,
@ -27,6 +29,7 @@ struct Rpc
int op; int op;
void *data; void *data;
int count; int count;
int hex; /* should result of read be turned into hex? */
}; };
struct Conv struct Conv
@ -214,9 +217,10 @@ extern int xiowrite(int, void*, int);
extern int xioasrdresp(int, void*, int); extern int xioasrdresp(int, void*, int);
extern int xioasgetticket(int, char*, char*); extern int xioasgetticket(int, char*, char*);
/* pkcs1.c */ /* pkcs1.c - maybe should be in libsec */
typedef DigestState *DigestAlg(uchar*, ulong, uchar*, DigestState*); typedef DigestState *DigestAlg(uchar*, ulong, uchar*, DigestState*);
int rsasign(RSApriv*, DigestAlg*, uchar*, uint, uchar*, uint); int rsasign(RSApriv*, DigestAlg*, uchar*, uint, uchar*, uint);
int rsaverify(RSApub*, DigestAlg*, uchar*, uint, uchar*, uint);
void mptoberjust(mpint*, uchar*, uint); void mptoberjust(mpint*, uchar*, uint);

View file

@ -23,7 +23,7 @@ xdsasign(Conv *c)
{ {
int n; int n;
mpint *m; mpint *m;
uchar digest[SHA1dlen]; uchar digest[SHA1dlen], sigblob[20+20];
DSAsig *sig; DSAsig *sig;
Key *k; Key *k;
@ -46,7 +46,13 @@ xdsasign(Conv *c)
mpfree(m); mpfree(m);
if(sig == nil) if(sig == nil)
return -1; 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); dsasigfree(sig);
return 0; return 0;
} }
@ -80,11 +86,11 @@ readdsapriv(Key *k)
|| (priv->pub.q=strtomp(a, nil, 16, nil))==nil) || (priv->pub.q=strtomp(a, nil, 16, nil))==nil)
goto Error; goto Error;
strlwr(a); 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) || (priv->pub.alpha=strtomp(a, nil, 16, nil))==nil)
goto Error; goto Error;
strlwr(a); 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) || (priv->pub.key=strtomp(a, nil, 16, nil))==nil)
goto Error; goto Error;
strlwr(a); strlwr(a);

View file

@ -166,7 +166,7 @@ static int
keylist(int i, char *a, uint nn) keylist(int i, char *a, uint nn)
{ {
int n; int n;
char buf[512]; char buf[4096];
Key *k; Key *k;
if(i >= ring.nkey) if(i >= ring.nkey)

View file

@ -36,7 +36,7 @@ rsasign(RSApriv *key, DigestAlg *hash, uchar *digest, uint dlen,
/* /*
* Create number to sign. * Create number to sign.
*/ */
len = (mpsignif(key->pub.n)+7)/8; len = (mpsignif(key->pub.n)+7)/8 - 1;
if(len < n+2){ if(len < n+2){
werrstr("rsa key too short"); werrstr("rsa key too short");
return -1; return -1;
@ -65,9 +65,41 @@ rsasign(RSApriv *key, DigestAlg *hash, uchar *digest, uint dlen,
mpfree(m); mpfree(m);
if(s == nil) if(s == nil)
return -1; return -1;
mptoberjust(s, sig, len); mptoberjust(s, sig, len+1);
mpfree(s); 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, * digestAlgorithm AlgorithmIdentifier,
* digest OCTET STRING * digest OCTET STRING
* } * }
*
* except that OpenSSL seems to sign
*
* DigestInfo ::= SEQUENCE {
* SEQUENCE{ digestAlgorithm AlgorithmIdentifier, NULL }
* digest OCTET STRING
* }
*
* instead. Sigh.
*/ */
static int static int
mkasn1(uchar *asn1, DigestAlg *alg, uchar *d, uint dlen) 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++ = 0x30; /* sequence */
p++; p++;
*p++ = 0x30; /* another sequence */
p++;
*p++ = 0x06; /* object id */ *p++ = 0x06; /* object id */
*p++ = olen; *p++ = olen;
memmove(p, obj, olen); memmove(p, obj, olen);
p += olen; p += olen;
*p++ = 0x05; /* null */
*p++ = 0;
asn1[3] = p - (asn1+4); /* end of inner sequence */
*p++ = 0x04; /* octet string */ *p++ = 0x04; /* octet string */
*p++ = dlen; *p++ = dlen;
memmove(p, d, dlen); memmove(p, d, dlen);
p += dlen; p += dlen;
asn1[1] = p - (asn1+2); asn1[1] = p - (asn1+2); /* end of outer sequence */
return p-asn1; return p-asn1;
} }

View file

@ -40,6 +40,8 @@ char *rpcname[] =
"read", "read",
"start", "start",
"write", "write",
"readhex",
"writehex",
}; };
static int static int
@ -153,7 +155,20 @@ rpcexec(Conv *c)
{ {
uchar *p; uchar *p;
c->rpc.hex = 0;
switch(c->rpc.op){ 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: case RpcRead:
if(c->rpc.count > 0){ if(c->rpc.count > 0){
rpcrespond(c, "error read takes no parameters"); rpcrespond(c, "error read takes no parameters");
@ -161,6 +176,7 @@ rpcexec(Conv *c)
} }
/* fall through */ /* fall through */
default: default:
Default:
if(!c->active){ if(!c->active){
if(c->done) if(c->done)
rpcrespond(c, "done"); rpcrespond(c, "done");
@ -224,11 +240,18 @@ void
rpcrespondn(Conv *c, char *verb, void *data, int count) rpcrespondn(Conv *c, char *verb, void *data, int count)
{ {
char *p; char *p;
int need, hex;
if(c->hangup) if(c->hangup)
return; 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)); print("RPC response too large; caller %#lux", getcallerpc(&c));
return; return;
} }
@ -236,8 +259,14 @@ rpcrespondn(Conv *c, char *verb, void *data, int count)
strcpy(c->reply, verb); strcpy(c->reply, verb);
p = c->reply + strlen(c->reply); p = c->reply + strlen(c->reply);
*p++ = ' '; *p++ = ' ';
memmove(p, data, count); if(hex){
c->nreply = count + (p - c->reply); 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->kickreply)(c);
c->rpc.op = RpcUnknown; c->rpc.op = RpcUnknown;
} }

View file

@ -4,65 +4,116 @@
/* /*
* RSA authentication. * RSA authentication.
* *
* Client: * Encrypt/Decrypt:
* start n=xxx ek=xxx * start n=xxx ek=xxx
* write msg * write msg
* read decrypt(msg) * read encrypt/decrypt(msg)
* *
* Sign (PKCS #1 using hash=sha1 or hash=md5) * Sign (PKCS #1 using hash=sha1 or hash=md5)
* start n=xxx ek=xxx * start n=xxx ek=xxx
* write hash(msg) * write hash(msg)
* read signature(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. * all numbers are hexadecimal biginits parsable with strtomp.
* must be lower case for attribute matching in start. * must be lower case for attribute matching in start.
*/ */
static int static int
rsaclient(Conv *c) xrsadecrypt(Conv *c)
{ {
char *chal; char *txt, buf[4096], *role;
mpint *m; int n, ret;
mpint *m, *mm;
Key *k; Key *k;
RSApriv *key;
ret = -1;
txt = nil;
m = nil;
mm = nil;
/* fetch key */
c->state = "keylookup";
k = keylookup("%A", c->attr); k = keylookup("%A", c->attr);
if(k == nil) if(k == nil)
return -1; goto out;
c->state = "read challenge"; key = k->priv;
if(convreadm(c, &chal) < 0){
keyclose(k); /* make sure have private half if needed */
return -1; 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: /* read text */
free(chal); c->state = "read";
convprint(c, "bad challenge"); if((n=convreadm(c, &txt)) < 0)
keyclose(k); goto out;
return -1; 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) if(m == nil)
goto badchal; goto out;
free(chal); if(strcmp(role, "decrypt") == 0)
m = rsadecrypt(k->priv, m, m); mm = rsadecrypt(key, m, m);
convprint(c, "%B", 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(m);
mpfree(mm);
keyclose(k); keyclose(k);
return 0; free(txt);
return ret;
} }
static int static int
xrsasign(Conv *c) xrsasign(Conv *c)
{ {
char *hash; char *hash, *role;
int dlen, n; int dlen, n, ret;
DigestAlg *hashfn; DigestAlg *hashfn;
Key *k; Key *k;
RSApriv *key;
uchar sig[1024], digest[64]; uchar sig[1024], digest[64];
char *sig2;
ret = -1;
/* fetch key */
c->state = "keylookup";
k = keylookup("%A", c->attr); k = keylookup("%A", c->attr);
if(k == nil) 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"); hash = strfindattr(k->attr, "hash");
if(hash == nil) if(hash == nil)
hash = "sha1"; hash = "sha1";
@ -74,20 +125,38 @@ xrsasign(Conv *c)
dlen = MD5dlen; dlen = MD5dlen;
}else{ }else{
werrstr("unknown hash function %s", hash); werrstr("unknown hash function %s", hash);
return -1; goto out;
} }
c->state = "read data";
if((n=convread(c, digest, dlen)) < 0){ /* read hash */
keyclose(k); c->state = "read hash";
return -1; 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); ret = 0;
n = rsasign(k->priv, hashfn, digest, dlen, sig, sizeof sig);
out:
keyclose(k); keyclose(k);
if(n < 0) return ret;
return -1;
convwrite(c, sig, n);
return 0;
} }
/* /*
@ -119,6 +188,9 @@ readrsapriv(Key *k)
|| (priv->pub.n=strtomp(a, nil, 16, nil))==nil) || (priv->pub.n=strtomp(a, nil, 16, nil))==nil)
goto Error; goto Error;
strlwr(a); strlwr(a);
if(k->privattr == nil) /* only public half */
return priv;
if((a=strfindattr(k->privattr, "!p"))==nil if((a=strfindattr(k->privattr, "!p"))==nil
|| (priv->p=strtomp(a, nil, 16, nil))==nil) || (priv->p=strtomp(a, nil, 16, nil))==nil)
goto Error; goto Error;
@ -177,8 +249,10 @@ rsaclose(Key *k)
static Role static Role
rsaroles[] = rsaroles[] =
{ {
"client", rsaclient,
"sign", xrsasign, "sign", xrsasign,
"verify", xrsasign, /* public operation */
"decrypt", xrsadecrypt,
"encrypt", xrsadecrypt, /* public operation */
0 0
}; };

View file

@ -494,7 +494,9 @@ main(int argc, char **argv)
char *serve, *tcpserve, *user; char *serve, *tcpserve, *user;
AuthConn *c; AuthConn *c;
serve = "$auth"; serve = getenv("secstore");
if(serve == nil)
serve = "secstore";
user = getuser(); user = getuser();
memset(Gflag, 0, sizeof Gflag); memset(Gflag, 0, sizeof Gflag);
fmtinstall('B', mpfmt); fmtinstall('B', mpfmt);
@ -559,14 +561,8 @@ main(int argc, char **argv)
exits("usage"); exits("usage");
} }
rc = strlen(serve)+sizeof("tcp!!99990"); tcpserve = netmkaddr(serve, "tcp", "secstore");
tcpserve = emalloc(rc);
if(strchr(serve,'!'))
strcpy(tcpserve, serve);
else
snprint(tcpserve, rc, "tcp!%s!5356", serve);
c = login(user, tcpserve, pass_stdin, pass_nvram); c = login(user, tcpserve, pass_stdin, pass_nvram);
free(tcpserve);
if(c == nil){ if(c == nil){
fprint(2, "secstore authentication failed\n"); fprint(2, "secstore authentication failed\n");
exits("secstore authentication failed"); exits("secstore authentication failed");

1047
src/cmd/auth/ssh-agent.c Normal file

File diff suppressed because it is too large Load diff