diff options
Diffstat (limited to 'src/cmd/auth/ssh-agent.c')
-rw-r--r-- | src/cmd/auth/ssh-agent.c | 1047 |
1 files changed, 1047 insertions, 0 deletions
diff --git a/src/cmd/auth/ssh-agent.c b/src/cmd/auth/ssh-agent.c new file mode 100644 index 00000000..f711ff06 --- /dev/null +++ b/src/cmd/auth/ssh-agent.c @@ -0,0 +1,1047 @@ +/* + * Present factotum in ssh agent clothing. + */ +#include <u.h> +#include <libc.h> +#include <mp.h> +#include <libsec.h> +#include <auth.h> +#include <thread.h> +#include <9pclient.h> + +enum +{ + STACK = 65536 +}; +enum /* agent protocol packet types */ +{ + SSH_AGENTC_NONE = 0, + SSH_AGENTC_REQUEST_RSA_IDENTITIES, + SSH_AGENT_RSA_IDENTITIES_ANSWER, + SSH_AGENTC_RSA_CHALLENGE, + SSH_AGENT_RSA_RESPONSE, + SSH_AGENT_FAILURE, + SSH_AGENT_SUCCESS, + SSH_AGENTC_ADD_RSA_IDENTITY, + SSH_AGENTC_REMOVE_RSA_IDENTITY, + SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES, + + SSH2_AGENTC_REQUEST_IDENTITIES = 11, + SSH2_AGENT_IDENTITIES_ANSWER, + SSH2_AGENTC_SIGN_REQUEST, + SSH2_AGENT_SIGN_RESPONSE, + + SSH2_AGENTC_ADD_IDENTITY = 17, + SSH2_AGENTC_REMOVE_IDENTITY, + SSH2_AGENTC_REMOVE_ALL_IDENTITIES, + SSH2_AGENTC_ADD_SMARTCARD_KEY, + SSH2_AGENTC_REMOVE_SMARTCARD_KEY, + + SSH_AGENTC_LOCK, + SSH_AGENTC_UNLOCK, + SSH_AGENTC_ADD_RSA_ID_CONSTRAINED, + SSH2_AGENTC_ADD_ID_CONSTRAINED, + SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED, + + SSH_AGENT_CONSTRAIN_LIFETIME = 1, + SSH_AGENT_CONSTRAIN_CONFIRM = 2, + + SSH2_AGENT_FAILURE = 30, + + SSH_COM_AGENT2_FAILURE = 102, + SSH_AGENT_OLD_SIGNATURE = 0x01, +}; + +typedef struct Aconn Aconn; +struct Aconn +{ + uchar *data; + uint ndata; + int ctl; + int fd; + char dir[40]; +}; + +typedef struct Msg Msg; +struct Msg +{ + uchar *bp; + uchar *p; + uchar *ep; +}; + +char adir[40]; +int afd; +int chatty; +char *factotum = "factotum"; + +void agentproc(void *v); +void* emalloc(int n); +void* erealloc(void *v, int n); +void listenproc(void *v); +int runmsg(Aconn *a); +void listkeystext(void); + +void +usage(void) +{ + fprint(2, "usage: 9 ssh-agent [-D] [factotum]\n"); + threadexitsall("usage"); +} + +void +threadmain(int argc, char **argv) +{ + int fd, pid, export, dotextlist; + char dir[100]; + char sock[200], addr[200]; + uvlong x; + + export = 0; + dotextlist = 0; + pid = getpid(); + fmtinstall('B', mpfmt); + fmtinstall('H', encodefmt); + fmtinstall('[', encodefmt); + + ARGBEGIN{ + case 'D': + chatty++; + break; + case 'e': + export = 1; + break; + case 'l': + dotextlist = 1; + break; + default: + usage(); + }ARGEND + + if(argc > 1) + usage(); + if(argc == 1) + factotum = argv[0]; + + if(dotextlist) + listkeystext(); + + x = ((uvlong)fastrand()<<32) | fastrand(); + x ^= ((uvlong)fastrand()<<32) | fastrand(); + snprint(dir, sizeof dir, "/tmp/ssh-%llux", x); + if((fd = create(dir, OREAD, DMDIR|0700)) < 0) + sysfatal("mkdir %s: %r", dir); + close(fd); + snprint(sock, sizeof sock, "%s/agent.%d", dir, pid); + snprint(addr, sizeof addr, "unix!%s", sock); + + if((afd = announce(addr, adir)) < 0) + sysfatal("announce %s: %r", addr); + + proccreate(listenproc, nil, STACK); + + print("SSH_AUTH_SOCK=%s;\n", sock); + if(export) + print("export SSH_AUTH_SOCK;\n"); + print("SSH_AGENT_PID=%d;\n", pid); + if(export) + print("export SSH_AGENT_PID;\n"); + close(1); + threadexits(0); +} + +void +listenproc(void *v) +{ + Aconn *a; + + USED(v); + for(;;){ + a = emalloc(sizeof *a); + a->ctl = listen(adir, a->dir); + if(a->ctl < 0) + sysfatal("listen: %r"); + proccreate(agentproc, a, STACK); + } +} + +void +agentproc(void *v) +{ + Aconn *a; + int n; + + a = v; + a->fd = accept(a->ctl, a->dir); + close(a->ctl); + a->ctl = -1; + for(;;){ + a->data = erealloc(a->data, a->ndata+1024); + n = read(a->fd, a->data+a->ndata, 1024); + if(n <= 0) + break; + a->ndata += n; + while(runmsg(a)) + ; + } + close(a->fd); + free(a); + threadexits(nil); +} + +int +get1(Msg *m) +{ + if(m->p >= m->ep) + return 0; + return *m->p++; +} + +int +get2(Msg *m) +{ + uint x; + + if(m->p+2 > m->ep) + return 0; + x = (m->p[0]<<8)|m->p[1]; + m->p += 2; + return x; +} + +int +get4(Msg *m) +{ + uint x; + if(m->p+4 > m->ep) + return 0; + x = (m->p[0]<<24)|(m->p[1]<<16)|(m->p[2]<<8)|m->p[3]; + m->p += 4; + return x; +} + +uchar* +getn(Msg *m, uint n) +{ + uchar *p; + + if(m->p+n > m->ep) + return nil; + p = m->p; + m->p += n; + return p; +} + +char* +getstr(Msg *m) +{ + uint n; + uchar *p; + + n = get4(m); + p = getn(m, n); + if(p == nil) + return nil; + p--; + memmove(p, p+1, n); + p[n] = 0; + return p; +} + +mpint* +getmp(Msg *m) +{ + int n; + uchar *p; + + n = (get2(m)+7)/8; + if((p=getn(m, n)) == nil) + return nil; + return betomp(p, n, nil); +} + +mpint* +getmp2(Msg *m) +{ + int n; + uchar *p; + + n = get4(m); + if((p = getn(m, n)) == nil) + return nil; + return betomp(p, n, nil); +} + +Msg* +getm(Msg *m, Msg *mm) +{ + uint n; + uchar *p; + + n = get4(m); + if((p = getn(m, n)) == nil) + return nil; + mm->bp = p; + mm->p = p; + mm->ep = p+n; + return mm; +} + +uchar* +ensure(Msg *m, int n) +{ + int len, plen; + uchar *p; + + len = m->ep - m->bp; + if(m->p+n > m->ep){ + plen = m->p - m->bp; + m->bp = erealloc(m->bp, len+n+1024); + m->p = m->bp+plen; + m->ep = m->bp+len+n+1024; + } + p = m->p; + m->p += n; + return p; +} + +void +put4(Msg *m, uint n) +{ + uchar *p; + + p = ensure(m, 4); + p[0] = (n>>24)&0xFF; + p[1] = (n>>16)&0xFF; + p[2] = (n>>8)&0xFF; + p[3] = n&0xFF; +} + +void +put2(Msg *m, uint n) +{ + uchar *p; + + p = ensure(m, 2); + p[0] = (n>>8)&0xFF; + p[1] = n&0xFF; +} + +void +put1(Msg *m, uint n) +{ + uchar *p; + + p = ensure(m, 1); + p[0] = n&0xFF; +} + +void +putn(Msg *m, void *a, uint n) +{ + uchar *p; + + p = ensure(m, n); + memmove(p, a, n); +} + +void +putmp(Msg *m, mpint *b) +{ + int bits, n; + uchar *p; + + bits = mpsignif(b); + put2(m, bits); + n = (bits+7)/8; + p = ensure(m, n); + mptobe(b, p, n, nil); +} + +void +putmp2(Msg *m, mpint *b) +{ + int bits, n; + uchar *p; + + if(mpcmp(b, mpzero) == 0){ + put4(m, 0); + return; + } + bits = mpsignif(b); + n = (bits+7)/8; + if(bits%8 == 0){ + put4(m, n+1); + put1(m, 0); + }else + put4(m, n); + p = ensure(m, n); + mptobe(b, p, n, nil); +} + +void +putstr(Msg *m, char *s) +{ + int n; + + n = strlen(s); + put4(m, n); + putn(m, s, n); +} + +void +putm(Msg *m, Msg *mm) +{ + uint n; + + n = mm->p - mm->bp; + put4(m, n); + putn(m, mm->bp, n); +} + +void +newmsg(Msg *m) +{ + memset(m, 0, sizeof *m); +} + +void +newreply(Msg *m, int type) +{ + memset(m, 0, sizeof *m); + put4(m, 0); + put1(m, type); +} + +void +reply(Aconn *a, Msg *m) +{ + uint n; + uchar *p; + + n = (m->p - m->bp) - 4; + p = m->bp; + p[0] = (n>>24)&0xFF; + p[1] = (n>>16)&0xFF; + p[2] = (n>>8)&0xFF; + p[3] = n&0xFF; + if(chatty) + fprint(2, "respond %d: %.*H\n", p[4], n, m->bp+4); + write(a->fd, p, n+4); + free(p); + memset(m, 0, sizeof *m); +} + +typedef struct Key Key; +struct Key +{ + mpint *mod; + mpint *ek; + char *comment; +}; + +static char* +find(char **f, int nf, char *k) +{ + int i, len; + + len = strlen(k); + for(i=1; i<nf; i++) /* i=1: f[0] is "key" */ + if(strncmp(f[i], k, len) == 0 && f[i][len] == '=') + return f[i]+len+1; + return nil; +} + +static int +putrsa1(Msg *m, char **f, int nf) +{ + char *p; + mpint *mod, *ek; + + p = find(f, nf, "n"); + if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil) + return -1; + p = find(f, nf, "ek"); + if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){ + mpfree(mod); + return -1; + } + p = find(f, nf, "comment"); + if(p == nil) + p = ""; + put4(m, mpsignif(mod)); + putmp(m, ek); + putmp(m, mod); + putstr(m, p); + mpfree(mod); + mpfree(ek); + return 0; +} + +void +printattr(char **f, int nf) +{ + int i; + + print("#"); + for(i=0; i<nf; i++) + print(" %s", f[i]); + print("\n"); +} + +void +printrsa1(char **f, int nf) +{ + char *p; + mpint *mod, *ek; + + p = find(f, nf, "n"); + if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil) + return; + p = find(f, nf, "ek"); + if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){ + mpfree(mod); + return; + } + p = find(f, nf, "comment"); + if(p == nil) + p = ""; + + if(chatty) + printattr(f, nf); + print("%d %.10B %.10B %s\n", mpsignif(mod), ek, mod, p); + mpfree(ek); + mpfree(mod); +} + +static int +putrsa(Msg *m, char **f, int nf) +{ + char *p; + mpint *mod, *ek; + + p = find(f, nf, "n"); + if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil) + return -1; + p = find(f, nf, "ek"); + if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){ + mpfree(mod); + return -1; + } + putstr(m, "ssh-rsa"); + putmp2(m, ek); + putmp2(m, mod); + mpfree(ek); + mpfree(mod); + return 0; +} + +RSApub* +getrsapub(Msg *m) +{ + RSApub *k; + + k = rsapuballoc(); + if(k == nil) + return nil; + k->ek = getmp2(m); + k->n = getmp2(m); + if(k->ek == nil || k->n == nil){ + rsapubfree(k); + return nil; + } + return k; +} + +static int +putdsa(Msg *m, char **f, int nf) +{ + char *p; + int ret; + mpint *dp, *dq, *dalpha, *dkey; + + ret = -1; + dp = dq = dalpha = dkey = nil; + p = find(f, nf, "p"); + if(p == nil || (dp = strtomp(p, nil, 16, nil)) == nil) + goto out; + p = find(f, nf, "q"); + if(p == nil || (dq = strtomp(p, nil, 16, nil)) == nil) + goto out; + p = find(f, nf, "alpha"); + if(p == nil || (dalpha = strtomp(p, nil, 16, nil)) == nil) + goto out; + p = find(f, nf, "key"); + if(p == nil || (dkey = strtomp(p, nil, 16, nil)) == nil) + goto out; + putstr(m, "ssh-dss"); + putmp2(m, dp); + putmp2(m, dq); + putmp2(m, dalpha); + putmp2(m, dkey); + ret = 0; +out: + mpfree(dp); + mpfree(dq); + mpfree(dalpha); + mpfree(dkey); + return ret; +} + +static int +putkey2(Msg *m, int (*put)(Msg*,char**,int), char **f, int nf) +{ + char *p; + Msg mm; + + newmsg(&mm); + if(put(&mm, f, nf) < 0) + return -1; + putm(m, &mm); + free(mm.bp); + p = find(f, nf, "comment"); + if(p == nil) + p = ""; + putstr(m, p); + return 0; +} + +static int +printkey(char *type, int (*put)(Msg*,char**,int), char **f, int nf) +{ + Msg m; + char *p; + + newmsg(&m); + if(put(&m, f, nf) < 0) + return -1; + p = find(f, nf, "comment"); + if(p == nil) + p = ""; + if(chatty) + printattr(f, nf); + print("%s %.*[ %s\n", type, m.p-m.bp, m.bp, p); + free(m.bp); + return 0; +} + +DSApub* +getdsapub(Msg *m) +{ + DSApub *k; + + k = dsapuballoc(); + if(k == nil) + return nil; + k->p = getmp2(m); + k->q = getmp2(m); + k->alpha = getmp2(m); + k->key = getmp2(m); + if(!k->p || !k->q || !k->alpha || !k->key){ + dsapubfree(k); + return nil; + } + return k; +} + +static int +listkeys(Msg *m, int version) +{ + char buf[8192+1], *line[100], *f[20], *p, *s; + uchar *pnk; + int i, n, nl, nf, nk; + CFid *fid; + + nk = 0; + pnk = m->p; + put4(m, 0); + if((fid = nsopen("factotum", nil, "ctl", OREAD)) == nil){ + fprint(2, "ssh-agent: open factotum: %r\n"); + return -1; + } + for(;;){ + if((n = fsread(fid, buf, sizeof buf-1)) <= 0) + break; + buf[n] = 0; + nl = getfields(buf, line, nelem(line), 1, "\n"); + for(i=0; i<nl; i++){ + nf = tokenize(line[i], f, nelem(f)); + if(nf == 0 || strcmp(f[0], "key") != 0) + continue; + p = find(f, nf, "proto"); + if(p == nil) + continue; + s = find(f, nf, "service"); + if(s == nil) + continue; + + if(version == 1 && strcmp(p, "rsa") == 0 && strcmp(s, "ssh") == 0) + if(putrsa1(m, f, nf) >= 0) + nk++; + if(version == 2 && strcmp(p, "rsa") == 0 && strcmp(s, "ssh-rsa") == 0) + if(putkey2(m, putrsa, f, nf) >= 0) + nk++; + if(version == 2 && strcmp(p, "dsa") == 0 && strcmp(s, "ssh-dss") == 0) + if(putkey2(m, putdsa, f, nf) >= 0) + nk++; + } + } + fsclose(fid); + pnk[0] = (nk>>24)&0xFF; + pnk[1] = (nk>>16)&0xFF; + pnk[2] = (nk>>8)&0xFF; + pnk[3] = nk&0xFF; + return nk; +} + +void +listkeystext(void) +{ + char buf[4096+1], *line[100], *f[20], *p, *s; + int i, n, nl, nf; + CFid *fid; + + if((fid = nsopen(factotum, nil, "ctl", OREAD)) == nil){ + fprint(2, "ssh-agent: open factotum: %r\n"); + return; + } + for(;;){ + if((n = fsread(fid, buf, sizeof buf-1)) <= 0) + break; + buf[n] = 0; + nl = getfields(buf, line, nelem(line), 1, "\n"); + for(i=0; i<nl; i++){ + nf = tokenize(line[i], f, nelem(f)); + if(nf == 0 || strcmp(f[0], "key") != 0) + continue; + p = find(f, nf, "proto"); + if(p == nil) + continue; + s = find(f, nf, "service"); + if(s == nil) + continue; + + if(strcmp(p, "rsa") == 0 && strcmp(s, "ssh") == 0) + printrsa1(f, nf); + if(strcmp(p, "rsa") == 0 && strcmp(s, "ssh-rsa") == 0) + printkey("ssh-rsa", putrsa, f, nf); + if(strcmp(p, "dsa") == 0 && strcmp(s, "ssh-dss") == 0) + printkey("ssh-dss", putdsa, f, nf); + } + } + fsclose(fid); + threadexitsall(nil); +} + +mpint* +rsaunpad(mpint *b) +{ + int i, n; + uchar buf[2560]; + + n = (mpsignif(b)+7)/8; + if(n > sizeof buf){ + werrstr("rsaunpad: too big"); + return nil; + } + mptobe(b, buf, n, nil); + + /* the initial zero has been eaten by the betomp -> mptobe sequence */ + if(buf[0] != 2){ + werrstr("rsaunpad: expected leading 2"); + return nil; + } + for(i=1; i<n; i++) + if(buf[i]==0) + break; + return betomp(buf+i, n-i, nil); +} + +void +mptoberjust(mpint *b, uchar *buf, int 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 +dorsa(Aconn *a, mpint *mod, mpint *exp, mpint *chal, uchar chalbuf[32]) +{ + AuthRpc *rpc; + mpint *m; + char buf[4096], *p; + mpint *decr, *unpad; + + USED(exp); + if((rpc = auth_allocrpc()) == nil){ + fprint(2, "ssh-agent: auth_allocrpc: %r\n"); + return -1; + } + snprint(buf, sizeof buf, "proto=rsa service=ssh role=client n=%lB ek=%lB", mod, exp); + if(chatty) + fprint(2, "ssh-agent: start %s\n", buf); + if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){ + fprint(2, "ssh-agent: auth 'start' failed: %r\n"); + Die: + auth_freerpc(rpc); + return -1; + } + m = nil; + if(auth_rpc(rpc, "read", nil, 0) != ARok){ + fprint(2, "ssh-agent: did not find negotiated key\n"); + goto Die; + } + if(chatty) + fprint(2, "read key %s\n", (char*)rpc->arg); + m = strtomp(rpc->arg, nil, 16, nil); + if(mpcmp(m, mod) != 0){ + fprint(2, "ssh-agent: found wrong key\n"); + mpfree(m); + goto Die; + } + mpfree(m); + + p = mptoa(chal, 16, nil, 0); + if(p == nil){ + fprint(2, "ssh-agent: dorsa: mptoa: %r\n"); + goto Die; + } + if(chatty) + fprint(2, "ssh-agent: challenge %B => %s\n", chal, p); + if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){ + fprint(2, "ssh-agent: dorsa: auth 'write': %r\n"); + free(p); + goto Die; + } + free(p); + if(auth_rpc(rpc, "read", nil, 0) != ARok){ + fprint(2, "ssh-agent: dorsa: auth 'read': %r\n"); + goto Die; + } + decr = strtomp(rpc->arg, nil, 16, nil); + if(chatty) + fprint(2, "ssh-agent: response %s => %B\n", rpc->arg, decr); + if(decr == nil){ + fprint(2, "ssh-agent: dorsa: strtomp: %r\n"); + goto Die; + } + unpad = rsaunpad(decr); + if(chatty) + fprint(2, "ssh-agent: unpad %B => %B\n", decr, unpad); + if(unpad == nil){ + fprint(2, "ssh-agent: dorsa: rsaunpad: %r\n"); + mpfree(decr); + goto Die; + } + mpfree(decr); + mptoberjust(unpad, chalbuf, 32); + mpfree(unpad); + auth_freerpc(rpc); + return 0; +} + +int +keysign(Msg *mkey, Msg *mdata, Msg *msig) +{ + char *s; + AuthRpc *rpc; + RSApub *rsa; + DSApub *dsa; + char buf[4096]; + uchar digest[SHA1dlen]; + + s = getstr(mkey); + if(strcmp(s, "ssh-rsa") == 0){ + rsa = getrsapub(mkey); + if(rsa == nil) + return -1; + snprint(buf, sizeof buf, "proto=rsa service=ssh-rsa role=sign n=%lB ek=%lB", + rsa->n, rsa->ek); + rsapubfree(rsa); + }else if(strcmp(s, "ssh-dss") == 0){ + dsa = getdsapub(mkey); + if(dsa == nil) + return -1; + snprint(buf, sizeof buf, "proto=dsa service=ssh-dss role=sign p=%lB q=%lB alpha=%lB key=%lB", + dsa->p, dsa->q, dsa->alpha, dsa->key); + dsapubfree(dsa); + }else{ + fprint(2, "ssh-agent: cannot sign key type %s\n", s); + werrstr("unknown key type %s", s); + return -1; + } + + if((rpc = auth_allocrpc()) == nil){ + fprint(2, "ssh-agent: auth_allocrpc: %r\n"); + return -1; + } + if(chatty) + fprint(2, "ssh-agent: start %s\n", buf); + if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){ + fprint(2, "ssh-agent: auth 'start' failed: %r\n"); + Die: + auth_freerpc(rpc); + return -1; + } + sha1(mdata->bp, mdata->ep-mdata->bp, digest, nil); + if(auth_rpc(rpc, "write", digest, SHA1dlen) != ARok){ + fprint(2, "ssh-agent: auth 'write in sign failed: %r\n"); + goto Die; + } + if(auth_rpc(rpc, "read", nil, 0) != ARok){ + fprint(2, "ssh-agent: auth 'read' failed: %r\n"); + goto Die; + } + newmsg(msig); + putstr(msig, s); + put4(msig, rpc->narg); + putn(msig, rpc->arg, rpc->narg); + auth_freerpc(rpc); + return 0; +} + +int +runmsg(Aconn *a) +{ + char *p; + int n, nk, type, rt, vers; + mpint *ek, *mod, *chal; + uchar sessid[16], chalbuf[32], digest[MD5dlen]; + uint len, flags; + DigestState *s; + Msg m, mkey, mdata, msig; + + if(a->ndata < 4) + return 0; + len = (a->data[0]<<24)|(a->data[1]<<16)|(a->data[2]<<8)|a->data[3]; + if(a->ndata < 4+len) + return 0; + m.p = a->data+4; + m.ep = m.p+len; + type = get1(&m); + if(chatty) + fprint(2, "msg %d: %.*H\n", type, len, m.p); + switch(type){ + default: + Failure: + newreply(&m, SSH_AGENT_FAILURE); + reply(a, &m); + break; + + case SSH_AGENTC_REQUEST_RSA_IDENTITIES: + vers = 1; + newreply(&m, SSH_AGENT_RSA_IDENTITIES_ANSWER); + goto Identities; + case SSH2_AGENTC_REQUEST_IDENTITIES: + vers = 2; + newreply(&m, SSH2_AGENT_IDENTITIES_ANSWER); + Identities: + nk = listkeys(&m, vers); + if(nk < 0){ + free(m.bp); + goto Failure; + } + if(chatty) + fprint(2, "request identities\n", nk); + reply(a, &m); + break; + + case SSH_AGENTC_RSA_CHALLENGE: + n = get4(&m); + ek = getmp(&m); + mod = getmp(&m); + chal = getmp(&m); + if((p = getn(&m, 16)) == nil){ + Failchal: + mpfree(ek); + mpfree(mod); + mpfree(chal); + goto Failure; + } + memmove(sessid, p, 16); + rt = get4(&m); + if(rt != 1 || dorsa(a, mod, ek, chal, chalbuf) < 0) + goto Failchal; + s = md5(chalbuf, 32, nil, nil); + if(s == nil) + goto Failchal; + md5(sessid, 16, digest, s); + + newreply(&m, SSH_AGENT_RSA_RESPONSE); + putn(&m, digest, 16); + reply(a, &m); + + mpfree(ek); + mpfree(mod); + mpfree(chal); + break; + + case SSH2_AGENTC_SIGN_REQUEST: + if(getm(&m, &mkey) < 0 + || getm(&m, &mdata) < 0) + goto Failure; + flags = get4(&m); + if(flags & SSH_AGENT_OLD_SIGNATURE) + goto Failure; + if(keysign(&mkey, &mdata, &msig) < 0) + goto Failure; + if(chatty) + fprint(2, "signature: %.*H\n", + msig.p-msig.bp, msig.bp); + newreply(&m, SSH2_AGENT_SIGN_RESPONSE); + putm(&m, &msig); + free(msig.bp); + reply(a, &m); + break; + + case SSH_AGENTC_ADD_RSA_IDENTITY: + /* + msg: n[4] mod[mp] pubexp[exp] privexp[mp] + p^-1 mod q[mp] p[mp] q[mp] comment[str] + */ + goto Failure; + + case SSH_AGENTC_REMOVE_RSA_IDENTITY: + /* + msg: n[4] mod[mp] pubexp[mp] + */ + goto Failure; + + } + + a->ndata -= 4+len; + memmove(a->data, a->data+4+len, a->ndata); + return 1; +} + +void* +emalloc(int n) +{ + void *v; + + v = mallocz(n, 1); + if(v == nil){ + abort(); + sysfatal("out of memory allocating %d", n); + } + return v; +} + +void* +erealloc(void *v, int n) +{ + v = realloc(v, n); + if(v == nil){ + abort(); + sysfatal("out of memory reallocating %d", n); + } + return v; +} + |