123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450 |
- #include "ssh.h"
- #include <bio.h>
- typedef struct Key Key;
- struct Key
- {
- mpint *mod;
- mpint *ek;
- char *comment;
- };
- typedef struct Achan Achan;
- struct Achan
- {
- int open;
- u32int chan; /* of remote */
- uchar lbuf[4];
- uint nlbuf;
- uint len;
- uchar *data;
- int ndata;
- int needeof;
- int needclosed;
- };
- Achan achan[16];
- 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
- listkeys(Key **kp)
- {
- Biobuf *b;
- Key *k;
- int nk;
- char *p, *f[20];
- int nf;
- mpint *mod, *ek;
-
- *kp = nil;
- if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil)
- return -1;
-
- k = nil;
- nk = 0;
- while((p = Brdline(b, '\n')) != nil){
- p[Blinelen(b)-1] = '\0';
- nf = tokenize(p, f, nelem(f));
- if(nf == 0 || strcmp(f[0], "key") != 0)
- continue;
- p = find(f, nf, "proto");
- if(p == nil || strcmp(p, "rsa") != 0)
- continue;
- p = find(f, nf, "n");
- if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil)
- continue;
- p = find(f, nf, "ek");
- if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){
- mpfree(mod);
- continue;
- }
- p = find(f, nf, "comment");
- if(p == nil)
- p = "";
- k = erealloc(k, (nk+1)*sizeof(k[0]));
- k[nk].mod = mod;
- k[nk].ek = ek;
- k[nk].comment = emalloc(strlen(p)+1);
- strcpy(k[nk].comment, p);
- nk++;
- }
- Bterm(b);
- *kp = k;
- return nk;
- }
- static int
- dorsa(mpint *mod, mpint *exp, mpint *chal, uchar chalbuf[32])
- {
- int afd;
- AuthRpc *rpc;
- mpint *m;
- char buf[4096], *p;
- mpint *decr, *unpad;
- USED(exp);
- snprint(buf, sizeof buf, "proto=rsa service=ssh role=client");
- if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
- debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n");
- return -1;
- }
- if((rpc = auth_allocrpc(afd)) == nil){
- debug(DBG_AUTH, "auth_allocrpc: %r\n");
- close(afd);
- return -1;
- }
- if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){
- debug(DBG_AUTH, "auth_rpc start failed: %r\n");
- Die:
- auth_freerpc(rpc);
- close(afd);
- return -1;
- }
- m = nil;
- debug(DBG_AUTH, "trying factotum rsa keys\n");
- while(auth_rpc(rpc, "read", nil, 0) == ARok){
- debug(DBG_AUTH, "try %s\n", (char*)rpc->arg);
- m = strtomp(rpc->arg, nil, 16, nil);
- if(mpcmp(m, mod) == 0)
- break;
- mpfree(m);
- m = nil;
- }
- if(m == nil)
- goto Die;
- mpfree(m);
-
- p = mptoa(chal, 16, nil, 0);
- if(p == nil){
- debug(DBG_AUTH, "\tmptoa failed: %r\n");
- goto Die;
- }
- if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){
- debug(DBG_AUTH, "\tauth_rpc write failed: %r\n");
- free(p);
- goto Die;
- }
- free(p);
- if(auth_rpc(rpc, "read", nil, 0) != ARok){
- debug(DBG_AUTH, "\tauth_rpc read failed: %r\n");
- goto Die;
- }
- decr = strtomp(rpc->arg, nil, 16, nil);
- if(decr == nil){
- debug(DBG_AUTH, "\tdecr %s failed\n", rpc->arg);
- goto Die;
- }
- debug(DBG_AUTH, "\tdecrypted %B\n", decr);
- unpad = rsaunpad(decr);
- if(unpad == nil){
- debug(DBG_AUTH, "\tunpad %B failed\n", decr);
- mpfree(decr);
- goto Die;
- }
- debug(DBG_AUTH, "\tunpadded %B\n", unpad);
- mpfree(decr);
- mptoberjust(unpad, chalbuf, 32);
- mpfree(unpad);
- auth_freerpc(rpc);
- close(afd);
- return 0;
- }
- int
- startagent(Conn *c)
- {
- int ret;
- Msg *m;
- m = allocmsg(c, SSH_CMSG_AGENT_REQUEST_FORWARDING, 0);
- sendmsg(m);
- m = recvmsg(c, -1);
- switch(m->type){
- case SSH_SMSG_SUCCESS:
- debug(DBG_AUTH, "agent allocated\n");
- ret = 0;
- break;
- case SSH_SMSG_FAILURE:
- debug(DBG_AUTH, "agent failed to allocate\n");
- ret = -1;
- break;
- default:
- badmsg(m, 0);
- ret = -1;
- break;
- }
- free(m);
- return ret;
- }
- void handlefullmsg(Conn*, Achan*);
- void
- handleagentmsg(Msg *m)
- {
- u32int chan, len;
- int n;
- Achan *a;
- assert(m->type == SSH_MSG_CHANNEL_DATA);
- debug(DBG_AUTH, "agent data\n");
- debug(DBG_AUTH, "\t%.*H\n", m->ep-m->rp, m->rp);
- chan = getlong(m);
- len = getlong(m);
- if(m->rp+len != m->ep)
- sysfatal("got bad channel data");
- if(chan >= nelem(achan))
- error("bad channel in agent request");
- a = &achan[chan];
- while(m->rp < m->ep){
- if(a->nlbuf < 4){
- a->lbuf[a->nlbuf++] = getbyte(m);
- if(a->nlbuf == 4){
- a->len = (a->lbuf[0]<<24) | (a->lbuf[1]<<16) | (a->lbuf[2]<<8) | a->lbuf[3];
- a->data = erealloc(a->data, a->len);
- a->ndata = 0;
- }
- continue;
- }
- if(a->ndata < a->len){
- n = a->len - a->ndata;
- if(n > m->ep - m->rp)
- n = m->ep - m->rp;
- memmove(a->data+a->ndata, getbytes(m, n), n);
- a->ndata += n;
- }
- if(a->ndata == a->len){
- handlefullmsg(m->c, a);
- a->nlbuf = 0;
- }
- }
- }
- void
- handlefullmsg(Conn *c, Achan *a)
- {
- int i;
- u32int chan, len, n, rt;
- uchar type;
- Msg *m, mm;
- Msg *r;
- Key *k;
- int nk;
- mpint *mod, *ek, *chal;
- uchar sessid[16];
- uchar chalbuf[32];
- uchar digest[16];
- DigestState *s;
- static int first;
- assert(a->len == a->ndata);
- chan = a->chan;
- mm.rp = a->data;
- mm.ep = a->data+a->ndata;
- mm.c = c;
- m = &mm;
- type = getbyte(m);
- if(first == 0){
- first++;
- fmtinstall('H', encodefmt);
- }
- switch(type){
- default:
- debug(DBG_AUTH, "unknown msg type\n");
- Failure:
- debug(DBG_AUTH, "agent sending failure\n");
- r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13);
- putlong(r, chan);
- putlong(r, 5);
- putlong(r, 1);
- putbyte(r, SSH_AGENT_FAILURE);
- sendmsg(r);
- return;
- case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
- debug(DBG_AUTH, "agent request identities\n");
- nk = listkeys(&k);
- if(nk < 0)
- goto Failure;
- len = 1+4; /* type, nk */
- for(i=0; i<nk; i++){
- len += 4;
- len += 2+(mpsignif(k[i].ek)+7)/8;
- len += 2+(mpsignif(k[i].mod)+7)/8;
- len += 4+strlen(k[i].comment);
- }
- r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+len);
- putlong(r, chan);
- putlong(r, len+4);
- putlong(r, len);
- putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER);
- putlong(r, nk);
- for(i=0; i<nk; i++){
- debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment);
- putlong(r, mpsignif(k[i].mod));
- putmpint(r, k[i].ek);
- putmpint(r, k[i].mod);
- putstring(r, k[i].comment);
- mpfree(k[i].ek);
- mpfree(k[i].mod);
- free(k[i].comment);
- }
- free(k);
- sendmsg(r);
- break;
- case SSH_AGENTC_RSA_CHALLENGE:
- n = getlong(m);
- USED(n); /* number of bits in key; who cares? */
- ek = getmpint(m);
- mod = getmpint(m);
- chal = getmpint(m);
- memmove(sessid, getbytes(m, 16), 16);
- rt = getlong(m);
- debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n",
- ek, mod, chal, rt, m->rp, m->ep);
- if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){
- mpfree(ek);
- mpfree(mod);
- mpfree(chal);
- goto Failure;
- }
- s = md5(chalbuf, 32, nil, nil);
- md5(sessid, 16, digest, s);
- r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16);
- putlong(r, chan);
- putlong(r, 4+16+1);
- putlong(r, 16+1);
- putbyte(r, SSH_AGENT_RSA_RESPONSE);
- putbytes(r, digest, 16);
- debug(DBG_AUTH, "digest %.16H\n", digest);
- sendmsg(r);
- mpfree(ek);
- mpfree(mod);
- mpfree(chal);
- return;
- case SSH_AGENTC_ADD_RSA_IDENTITY:
- goto Failure;
- /*
- n = getlong(m);
- pubmod = getmpint(m);
- pubexp = getmpint(m);
- privexp = getmpint(m);
- pinversemodq = getmpint(m);
- p = getmpint(m);
- q = getmpint(m);
- comment = getstring(m);
- add to factotum;
- send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
- */
- case SSH_AGENTC_REMOVE_RSA_IDENTITY:
- goto Failure;
- /*
- n = getlong(m);
- pubmod = getmpint(m);
- pubexp = getmpint(m);
- tell factotum to del key
- send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
- */
- }
- }
- void
- handleagentopen(Msg *m)
- {
- int i;
- u32int remote;
- assert(m->type == SSH_SMSG_AGENT_OPEN);
- remote = getlong(m);
- debug(DBG_AUTH, "agent open %d\n", remote);
- for(i=0; i<nelem(achan); i++)
- if(achan[i].open == 0 && achan[i].needeof == 0 && achan[i].needclosed == 0)
- break;
- if(i == nelem(achan)){
- m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_FAILURE, 4);
- putlong(m, remote);
- sendmsg(m);
- return;
- }
- debug(DBG_AUTH, "\tremote %d is local %d\n", remote, i);
- achan[i].open = 1;
- achan[i].needeof = 1;
- achan[i].needclosed = 1;
- achan[i].nlbuf = 0;
- achan[i].chan = remote;
- m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 8);
- putlong(m, remote);
- putlong(m, i);
- sendmsg(m);
- }
- void
- handleagentieof(Msg *m)
- {
- u32int local;
- assert(m->type == SSH_MSG_CHANNEL_INPUT_EOF);
- local = getlong(m);
- debug(DBG_AUTH, "agent close %d\n", local);
- if(local < nelem(achan)){
- debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
- achan[local].open = 0;
- /*
- m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
- putlong(m, achan[local].chan);
- sendmsg(m);
- */
- if(achan[local].needeof){
- achan[local].needeof = 0;
- m = allocmsg(m->c, SSH_MSG_CHANNEL_INPUT_EOF, 4);
- putlong(m, achan[local].chan);
- sendmsg(m);
- }
- }
- }
- void
- handleagentoclose(Msg *m)
- {
- u32int local;
- assert(m->type == SSH_MSG_CHANNEL_OUTPUT_CLOSED);
- local = getlong(m);
- debug(DBG_AUTH, "agent close %d\n", local);
- if(local < nelem(achan)){
- debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
- if(achan[local].needclosed){
- achan[local].needclosed = 0;
- m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
- putlong(m, achan[local].chan);
- sendmsg(m);
- }
- }
- }
|