4 typedef struct Key Key;
12 typedef struct Achan Achan;
16 u32int chan; /* of remote */
29 find(char **f, int nf, char *k)
34 for(i=1; i<nf; i++) /* i=1: f[0] is "key" */
35 if(strncmp(f[i], k, len) == 0 && f[i][len] == '=')
51 if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil)
56 while((p = Brdline(b, '\n')) != nil){
57 p[Blinelen(b)-1] = '\0';
58 nf = tokenize(p, f, nelem(f));
59 if(nf == 0 || strcmp(f[0], "key") != 0)
61 p = find(f, nf, "proto");
62 if(p == nil || strcmp(p, "rsa") != 0)
65 if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil)
67 p = find(f, nf, "ek");
68 if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){
72 p = find(f, nf, "comment");
75 k = erealloc(k, (nk+1)*sizeof(k[0]));
78 k[nk].comment = emalloc(strlen(p)+1);
79 strcpy(k[nk].comment, p);
89 dorsa(mpint *mod, mpint *exp, mpint *chal, uchar chalbuf[32])
99 snprint(buf, sizeof buf, "proto=rsa service=ssh role=client");
100 if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
101 debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n");
104 if((rpc = auth_allocrpc(afd)) == nil){
105 debug(DBG_AUTH, "auth_allocrpc: %r\n");
109 if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){
110 debug(DBG_AUTH, "auth_rpc start failed: %r\n");
117 debug(DBG_AUTH, "trying factotum rsa keys\n");
118 while(auth_rpc(rpc, "read", nil, 0) == ARok){
119 debug(DBG_AUTH, "try %s\n", (char*)rpc->arg);
120 m = strtomp(rpc->arg, nil, 16, nil);
121 if(mpcmp(m, mod) == 0)
130 p = mptoa(chal, 16, nil, 0);
132 debug(DBG_AUTH, "\tmptoa failed: %r\n");
135 if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){
136 debug(DBG_AUTH, "\tauth_rpc write failed: %r\n");
141 if(auth_rpc(rpc, "read", nil, 0) != ARok){
142 debug(DBG_AUTH, "\tauth_rpc read failed: %r\n");
145 decr = strtomp(rpc->arg, nil, 16, nil);
147 debug(DBG_AUTH, "\tdecr %s failed\n", rpc->arg);
150 debug(DBG_AUTH, "\tdecrypted %B\n", decr);
151 unpad = rsaunpad(decr);
153 debug(DBG_AUTH, "\tunpad %B failed\n", decr);
157 debug(DBG_AUTH, "\tunpadded %B\n", unpad);
159 mptoberjust(unpad, chalbuf, 32);
172 m = allocmsg(c, SSH_CMSG_AGENT_REQUEST_FORWARDING, 0);
177 case SSH_SMSG_SUCCESS:
178 debug(DBG_AUTH, "agent allocated\n");
181 case SSH_SMSG_FAILURE:
182 debug(DBG_AUTH, "agent failed to allocate\n");
194 void handlefullmsg(Conn*, Achan*);
197 handleagentmsg(Msg *m)
203 assert(m->type == SSH_MSG_CHANNEL_DATA);
205 debug(DBG_AUTH, "agent data\n");
206 debug(DBG_AUTH, "\t%.*H\n", (int)(m->ep - m->rp), m->rp);
209 if(m->rp+len != m->ep)
210 sysfatal("got bad channel data");
212 if(chan >= nelem(achan))
213 error("bad channel in agent request");
217 while(m->rp < m->ep){
219 a->lbuf[a->nlbuf++] = getbyte(m);
221 a->len = (a->lbuf[0]<<24) | (a->lbuf[1]<<16) | (a->lbuf[2]<<8) | a->lbuf[3];
222 a->data = erealloc(a->data, a->len);
227 if(a->ndata < a->len){
228 n = a->len - a->ndata;
229 if(n > m->ep - m->rp)
231 memmove(a->data+a->ndata, getbytes(m, n), n);
234 if(a->ndata == a->len){
235 handlefullmsg(m->c, a);
242 handlefullmsg(Conn *c, Achan *a)
245 u32int chan, len, n, rt;
251 mpint *mod, *ek, *chal;
258 assert(a->len == a->ndata);
262 mm.ep = a->data+a->ndata;
270 fmtinstall('H', encodefmt);
275 debug(DBG_AUTH, "unknown msg type\n");
277 debug(DBG_AUTH, "agent sending failure\n");
278 r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13);
282 putbyte(r, SSH_AGENT_FAILURE);
286 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
287 debug(DBG_AUTH, "agent request identities\n");
291 len = 1+4; /* type, nk */
294 len += 2+(mpsignif(k[i].ek)+7)/8;
295 len += 2+(mpsignif(k[i].mod)+7)/8;
296 len += 4+strlen(k[i].comment);
298 r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+len);
302 putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER);
305 debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment);
306 putlong(r, mpsignif(k[i].mod));
307 putmpint(r, k[i].ek);
308 putmpint(r, k[i].mod);
309 putstring(r, k[i].comment);
318 case SSH_AGENTC_RSA_CHALLENGE:
320 USED(n); /* number of bits in key; who cares? */
324 memmove(sessid, getbytes(m, 16), 16);
326 debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n",
327 ek, mod, chal, rt, m->rp, m->ep);
328 if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){
334 s = md5(chalbuf, 32, nil, nil);
335 md5(sessid, 16, digest, s);
336 r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16);
340 putbyte(r, SSH_AGENT_RSA_RESPONSE);
341 putbytes(r, digest, 16);
342 debug(DBG_AUTH, "digest %.16H\n", digest);
349 case SSH_AGENTC_ADD_RSA_IDENTITY:
353 pubmod = getmpint(m);
354 pubexp = getmpint(m);
355 privexp = getmpint(m);
356 pinversemodq = getmpint(m);
359 comment = getstring(m);
361 send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
364 case SSH_AGENTC_REMOVE_RSA_IDENTITY:
368 pubmod = getmpint(m);
369 pubexp = getmpint(m);
370 tell factotum to del key
371 send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
377 handleagentopen(Msg *m)
382 assert(m->type == SSH_SMSG_AGENT_OPEN);
384 debug(DBG_AUTH, "agent open %d\n", remote);
386 for(i=0; i<nelem(achan); i++)
387 if(achan[i].open == 0 && achan[i].needeof == 0 && achan[i].needclosed == 0)
389 if(i == nelem(achan)){
390 m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_FAILURE, 4);
396 debug(DBG_AUTH, "\tremote %d is local %d\n", remote, i);
398 achan[i].needeof = 1;
399 achan[i].needclosed = 1;
401 achan[i].chan = remote;
402 m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 8);
409 handleagentieof(Msg *m)
413 assert(m->type == SSH_MSG_CHANNEL_INPUT_EOF);
415 debug(DBG_AUTH, "agent close %d\n", local);
416 if(local < nelem(achan)){
417 debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
418 achan[local].open = 0;
420 m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
421 putlong(m, achan[local].chan);
424 if(achan[local].needeof){
425 achan[local].needeof = 0;
426 m = allocmsg(m->c, SSH_MSG_CHANNEL_INPUT_EOF, 4);
427 putlong(m, achan[local].chan);
434 handleagentoclose(Msg *m)
438 assert(m->type == SSH_MSG_CHANNEL_OUTPUT_CLOSED);
440 debug(DBG_AUTH, "agent close %d\n", local);
441 if(local < nelem(achan)){
442 debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
443 if(achan[local].needclosed){
444 achan[local].needclosed = 0;
445 m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
446 putlong(m, achan[local].chan);