Blob


1 /*
2 * Present factotum in ssh agent clothing.
3 */
4 #include <u.h>
5 #include <libc.h>
6 #include <mp.h>
7 #include <libsec.h>
8 #include <auth.h>
9 #include <thread.h>
10 #include <9pclient.h>
12 enum
13 {
14 STACK = 65536
15 };
16 enum /* agent protocol packet types */
17 {
18 SSH_AGENTC_NONE = 0,
19 SSH_AGENTC_REQUEST_RSA_IDENTITIES,
20 SSH_AGENT_RSA_IDENTITIES_ANSWER,
21 SSH_AGENTC_RSA_CHALLENGE,
22 SSH_AGENT_RSA_RESPONSE,
23 SSH_AGENT_FAILURE,
24 SSH_AGENT_SUCCESS,
25 SSH_AGENTC_ADD_RSA_IDENTITY,
26 SSH_AGENTC_REMOVE_RSA_IDENTITY,
27 SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES,
29 SSH2_AGENTC_REQUEST_IDENTITIES = 11,
30 SSH2_AGENT_IDENTITIES_ANSWER,
31 SSH2_AGENTC_SIGN_REQUEST,
32 SSH2_AGENT_SIGN_RESPONSE,
34 SSH2_AGENTC_ADD_IDENTITY = 17,
35 SSH2_AGENTC_REMOVE_IDENTITY,
36 SSH2_AGENTC_REMOVE_ALL_IDENTITIES,
37 SSH2_AGENTC_ADD_SMARTCARD_KEY,
38 SSH2_AGENTC_REMOVE_SMARTCARD_KEY,
40 SSH_AGENTC_LOCK,
41 SSH_AGENTC_UNLOCK,
42 SSH_AGENTC_ADD_RSA_ID_CONSTRAINED,
43 SSH2_AGENTC_ADD_ID_CONSTRAINED,
44 SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED,
46 SSH_AGENT_CONSTRAIN_LIFETIME = 1,
47 SSH_AGENT_CONSTRAIN_CONFIRM = 2,
49 SSH2_AGENT_FAILURE = 30,
51 SSH_COM_AGENT2_FAILURE = 102,
52 SSH_AGENT_OLD_SIGNATURE = 0x01
53 };
55 typedef struct Aconn Aconn;
56 struct Aconn
57 {
58 uchar *data;
59 uint ndata;
60 int ctl;
61 int fd;
62 char dir[40];
63 };
65 typedef struct Msg Msg;
66 struct Msg
67 {
68 uchar *bp;
69 uchar *p;
70 uchar *ep;
71 int bpalloc;
72 };
74 char adir[40];
75 int afd;
76 int chatty;
77 char *factotum = "factotum";
79 void agentproc(void *v);
80 void* emalloc(int n);
81 void* erealloc(void *v, int n);
82 void listenproc(void *v);
83 int runmsg(Aconn *a);
84 void listkeystext(void);
86 void
87 usage(void)
88 {
89 fprint(2, "usage: 9 ssh-agent [-D] [factotum]\n");
90 threadexitsall("usage");
91 }
93 void
94 threadmain(int argc, char **argv)
95 {
96 int fd, pid, export, dotextlist;
97 char dir[100], *ns;
98 char sock[200], addr[200];
99 uvlong x;
101 export = 0;
102 dotextlist = 0;
103 pid = getpid();
104 fmtinstall('B', mpfmt);
105 fmtinstall('H', encodefmt);
106 fmtinstall('[', encodefmt);
108 ARGBEGIN{
109 case '9':
110 chatty9pclient++;
111 break;
112 case 'D':
113 chatty++;
114 break;
115 case 'e':
116 export = 1;
117 break;
118 case 'l':
119 dotextlist = 1;
120 break;
121 default:
122 usage();
123 }ARGEND
125 if(argc > 1)
126 usage();
127 if(argc == 1)
128 factotum = argv[0];
130 if(dotextlist)
131 listkeystext();
133 ns = getns();
134 snprint(sock, sizeof sock, "%s/ssh-agent.socket", ns);
135 if(0){
136 x = ((uvlong)fastrand()<<32) | fastrand();
137 x ^= ((uvlong)fastrand()<<32) | fastrand();
138 snprint(dir, sizeof dir, "/tmp/ssh-%llux", x);
139 if((fd = create(dir, OREAD, DMDIR|0700)) < 0)
140 sysfatal("mkdir %s: %r", dir);
141 close(fd);
142 snprint(sock, sizeof sock, "%s/agent.%d", dir, pid);
144 snprint(addr, sizeof addr, "unix!%s", sock);
146 if((afd = announce(addr, adir)) < 0)
147 sysfatal("announce %s: %r", addr);
149 print("SSH_AUTH_SOCK=%s;\n", sock);
150 if(export)
151 print("export SSH_AUTH_SOCK;\n");
152 print("SSH_AGENT_PID=%d;\n", pid);
153 if(export)
154 print("export SSH_AGENT_PID;\n");
155 close(1);
156 rfork(RFNOTEG);
157 proccreate(listenproc, nil, STACK);
158 threadexits(0);
161 void
162 listenproc(void *v)
164 Aconn *a;
166 USED(v);
167 for(;;){
168 a = emalloc(sizeof *a);
169 a->ctl = listen(adir, a->dir);
170 if(a->ctl < 0)
171 sysfatal("listen: %r");
172 proccreate(agentproc, a, STACK);
176 void
177 agentproc(void *v)
179 Aconn *a;
180 int n;
182 a = v;
183 a->fd = accept(a->ctl, a->dir);
184 close(a->ctl);
185 a->ctl = -1;
186 for(;;){
187 a->data = erealloc(a->data, a->ndata+1024);
188 n = read(a->fd, a->data+a->ndata, 1024);
189 if(n <= 0)
190 break;
191 a->ndata += n;
192 while(runmsg(a))
195 close(a->fd);
196 free(a);
197 threadexits(nil);
200 int
201 get1(Msg *m)
203 if(m->p >= m->ep)
204 return 0;
205 return *m->p++;
208 int
209 get2(Msg *m)
211 uint x;
213 if(m->p+2 > m->ep)
214 return 0;
215 x = (m->p[0]<<8)|m->p[1];
216 m->p += 2;
217 return x;
220 int
221 get4(Msg *m)
223 uint x;
224 if(m->p+4 > m->ep)
225 return 0;
226 x = (m->p[0]<<24)|(m->p[1]<<16)|(m->p[2]<<8)|m->p[3];
227 m->p += 4;
228 return x;
231 uchar*
232 getn(Msg *m, uint n)
234 uchar *p;
236 if(m->p+n > m->ep)
237 return nil;
238 p = m->p;
239 m->p += n;
240 return p;
243 char*
244 getstr(Msg *m)
246 uint n;
247 uchar *p;
249 n = get4(m);
250 p = getn(m, n);
251 if(p == nil)
252 return nil;
253 p--;
254 memmove(p, p+1, n);
255 p[n] = 0;
256 return (char*)p;
259 mpint*
260 getmp(Msg *m)
262 int n;
263 uchar *p;
265 n = (get2(m)+7)/8;
266 if((p=getn(m, n)) == nil)
267 return nil;
268 return betomp(p, n, nil);
271 mpint*
272 getmp2(Msg *m)
274 int n;
275 uchar *p;
277 n = get4(m);
278 if((p = getn(m, n)) == nil)
279 return nil;
280 return betomp(p, n, nil);
283 void
284 newmsg(Msg *m)
286 memset(m, 0, sizeof *m);
289 void
290 mreset(Msg *m)
292 if(m->bpalloc){
293 memset(m->bp, 0, m->ep-m->bp);
294 free(m->bp);
296 memset(m, 0, sizeof *m);
299 Msg*
300 getm(Msg *m, Msg *mm)
302 uint n;
303 uchar *p;
305 n = get4(m);
306 if((p = getn(m, n)) == nil)
307 return nil;
308 mm->bp = p;
309 mm->p = p;
310 mm->ep = p+n;
311 mm->bpalloc = 0;
312 return mm;
315 uchar*
316 ensure(Msg *m, int n)
318 int len;
319 uchar *p;
320 uchar *obp;
322 if(m->bp == nil)
323 m->bpalloc = 1;
324 if(!m->bpalloc){
325 p = emalloc(m->ep - m->bp);
326 memmove(p, m->bp, m->ep - m->bp);
327 obp = m->bp;
328 m->bp = p;
329 m->ep += m->bp - obp;
330 m->p += m->bp - obp;
331 m->bpalloc = 1;
333 len = m->ep - m->bp;
334 if(m->p+n > m->ep){
335 obp = m->bp;
336 m->bp = erealloc(m->bp, len+n+1024);
337 m->p += m->bp - obp;
338 m->ep += m->bp - obp;
339 m->ep += n+1024;
341 p = m->p;
342 m->p += n;
343 return p;
346 void
347 put4(Msg *m, uint n)
349 uchar *p;
351 p = ensure(m, 4);
352 p[0] = (n>>24)&0xFF;
353 p[1] = (n>>16)&0xFF;
354 p[2] = (n>>8)&0xFF;
355 p[3] = n&0xFF;
358 void
359 put2(Msg *m, uint n)
361 uchar *p;
363 p = ensure(m, 2);
364 p[0] = (n>>8)&0xFF;
365 p[1] = n&0xFF;
368 void
369 put1(Msg *m, uint n)
371 uchar *p;
373 p = ensure(m, 1);
374 p[0] = n&0xFF;
377 void
378 putn(Msg *m, void *a, uint n)
380 uchar *p;
382 p = ensure(m, n);
383 memmove(p, a, n);
386 void
387 putmp(Msg *m, mpint *b)
389 int bits, n;
390 uchar *p;
392 bits = mpsignif(b);
393 put2(m, bits);
394 n = (bits+7)/8;
395 p = ensure(m, n);
396 mptobe(b, p, n, nil);
399 void
400 putmp2(Msg *m, mpint *b)
402 int bits, n;
403 uchar *p;
405 if(mpcmp(b, mpzero) == 0){
406 put4(m, 0);
407 return;
409 bits = mpsignif(b);
410 n = (bits+7)/8;
411 if(bits%8 == 0){
412 put4(m, n+1);
413 put1(m, 0);
414 }else
415 put4(m, n);
416 p = ensure(m, n);
417 mptobe(b, p, n, nil);
420 void
421 putstr(Msg *m, char *s)
423 int n;
425 n = strlen(s);
426 put4(m, n);
427 putn(m, s, n);
430 void
431 putm(Msg *m, Msg *mm)
433 uint n;
435 n = mm->p - mm->bp;
436 put4(m, n);
437 putn(m, mm->bp, n);
440 void
441 newreply(Msg *m, int type)
443 memset(m, 0, sizeof *m);
444 put4(m, 0);
445 put1(m, type);
448 void
449 reply(Aconn *a, Msg *m)
451 uint n;
452 uchar *p;
454 n = (m->p - m->bp) - 4;
455 p = m->bp;
456 p[0] = (n>>24)&0xFF;
457 p[1] = (n>>16)&0xFF;
458 p[2] = (n>>8)&0xFF;
459 p[3] = n&0xFF;
460 if(chatty)
461 fprint(2, "respond %d t=%d: %.*H\n", n, p[4], n, m->bp+4);
462 write(a->fd, p, n+4);
463 mreset(m);
466 typedef struct Key Key;
467 struct Key
469 mpint *mod;
470 mpint *ek;
471 char *comment;
472 };
474 static char*
475 find(char **f, int nf, char *k)
477 int i, len;
479 len = strlen(k);
480 for(i=1; i<nf; i++) /* i=1: f[0] is "key" */
481 if(strncmp(f[i], k, len) == 0 && f[i][len] == '=')
482 return f[i]+len+1;
483 return nil;
486 static int
487 putrsa1(Msg *m, char **f, int nf)
489 char *p;
490 mpint *mod, *ek;
492 p = find(f, nf, "n");
493 if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil)
494 return -1;
495 p = find(f, nf, "ek");
496 if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){
497 mpfree(mod);
498 return -1;
500 p = find(f, nf, "comment");
501 if(p == nil)
502 p = "";
503 put4(m, mpsignif(mod));
504 putmp(m, ek);
505 putmp(m, mod);
506 putstr(m, p);
507 mpfree(mod);
508 mpfree(ek);
509 return 0;
512 void
513 printattr(char **f, int nf)
515 int i;
517 print("#");
518 for(i=0; i<nf; i++)
519 print(" %s", f[i]);
520 print("\n");
523 void
524 printrsa1(char **f, int nf)
526 char *p;
527 mpint *mod, *ek;
529 p = find(f, nf, "n");
530 if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil)
531 return;
532 p = find(f, nf, "ek");
533 if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){
534 mpfree(mod);
535 return;
537 p = find(f, nf, "comment");
538 if(p == nil)
539 p = "";
541 if(chatty)
542 printattr(f, nf);
543 print("%d %.10B %.10B %s\n", mpsignif(mod), ek, mod, p);
544 mpfree(ek);
545 mpfree(mod);
548 static int
549 putrsa(Msg *m, char **f, int nf)
551 char *p;
552 mpint *mod, *ek;
554 p = find(f, nf, "n");
555 if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil)
556 return -1;
557 p = find(f, nf, "ek");
558 if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){
559 mpfree(mod);
560 return -1;
562 putstr(m, "ssh-rsa");
563 putmp2(m, ek);
564 putmp2(m, mod);
565 mpfree(ek);
566 mpfree(mod);
567 return 0;
570 RSApub*
571 getrsapub(Msg *m)
573 RSApub *k;
575 k = rsapuballoc();
576 if(k == nil)
577 return nil;
578 k->ek = getmp2(m);
579 k->n = getmp2(m);
580 if(k->ek == nil || k->n == nil){
581 rsapubfree(k);
582 return nil;
584 return k;
587 static int
588 putdsa(Msg *m, char **f, int nf)
590 char *p;
591 int ret;
592 mpint *dp, *dq, *dalpha, *dkey;
594 ret = -1;
595 dp = dq = dalpha = dkey = nil;
596 p = find(f, nf, "p");
597 if(p == nil || (dp = strtomp(p, nil, 16, nil)) == nil)
598 goto out;
599 p = find(f, nf, "q");
600 if(p == nil || (dq = strtomp(p, nil, 16, nil)) == nil)
601 goto out;
602 p = find(f, nf, "alpha");
603 if(p == nil || (dalpha = strtomp(p, nil, 16, nil)) == nil)
604 goto out;
605 p = find(f, nf, "key");
606 if(p == nil || (dkey = strtomp(p, nil, 16, nil)) == nil)
607 goto out;
608 putstr(m, "ssh-dss");
609 putmp2(m, dp);
610 putmp2(m, dq);
611 putmp2(m, dalpha);
612 putmp2(m, dkey);
613 ret = 0;
614 out:
615 mpfree(dp);
616 mpfree(dq);
617 mpfree(dalpha);
618 mpfree(dkey);
619 return ret;
622 static int
623 putkey2(Msg *m, int (*put)(Msg*,char**,int), char **f, int nf)
625 char *p;
626 Msg mm;
628 newmsg(&mm);
629 if(put(&mm, f, nf) < 0)
630 return -1;
631 putm(m, &mm);
632 mreset(&mm);
633 p = find(f, nf, "comment");
634 if(p == nil)
635 p = "";
636 putstr(m, p);
637 return 0;
640 static int
641 printkey(char *type, int (*put)(Msg*,char**,int), char **f, int nf)
643 Msg m;
644 char *p;
646 newmsg(&m);
647 if(put(&m, f, nf) < 0)
648 return -1;
649 p = find(f, nf, "comment");
650 if(p == nil)
651 p = "";
652 if(chatty)
653 printattr(f, nf);
654 print("%s %.*[ %s\n", type, m.p-m.bp, m.bp, p);
655 mreset(&m);
656 return 0;
659 DSApub*
660 getdsapub(Msg *m)
662 DSApub *k;
664 k = dsapuballoc();
665 if(k == nil)
666 return nil;
667 k->p = getmp2(m);
668 k->q = getmp2(m);
669 k->alpha = getmp2(m);
670 k->key = getmp2(m);
671 if(!k->p || !k->q || !k->alpha || !k->key){
672 dsapubfree(k);
673 return nil;
675 return k;
678 static int
679 listkeys(Msg *m, int version)
681 char buf[8192+1], *line[100], *f[20], *p, *s;
682 int pnk;
683 int i, n, nl, nf, nk;
684 CFid *fid;
686 nk = 0;
687 pnk = m->p - m->bp;
688 put4(m, 0);
689 if((fid = nsopen(factotum, nil, "ctl", OREAD)) == nil){
690 fprint(2, "ssh-agent: open factotum: %r\n");
691 return -1;
693 for(;;){
694 if((n = fsread(fid, buf, sizeof buf-1)) <= 0)
695 break;
696 buf[n] = 0;
697 nl = getfields(buf, line, nelem(line), 1, "\n");
698 for(i=0; i<nl; i++){
699 nf = tokenize(line[i], f, nelem(f));
700 if(nf == 0 || strcmp(f[0], "key") != 0)
701 continue;
702 p = find(f, nf, "proto");
703 if(p == nil)
704 continue;
705 s = find(f, nf, "service");
706 if(s == nil)
707 continue;
709 if(version == 1 && strcmp(p, "rsa") == 0 && strcmp(s, "ssh") == 0)
710 if(putrsa1(m, f, nf) >= 0)
711 nk++;
712 if(version == 2 && strcmp(p, "rsa") == 0 && strcmp(s, "ssh-rsa") == 0)
713 if(putkey2(m, putrsa, f, nf) >= 0)
714 nk++;
715 if(version == 2 && strcmp(p, "dsa") == 0 && strcmp(s, "ssh-dss") == 0)
716 if(putkey2(m, putdsa, f, nf) >= 0)
717 nk++;
720 if(chatty)
721 fprint(2, "sending %d keys\n", nk);
722 fsclose(fid);
723 m->bp[pnk+0] = (nk>>24)&0xFF;
724 m->bp[pnk+1] = (nk>>16)&0xFF;
725 m->bp[pnk+2] = (nk>>8)&0xFF;
726 m->bp[pnk+3] = nk&0xFF;
727 return nk;
730 void
731 listkeystext(void)
733 char buf[8192+1], *line[100], *f[20], *p, *s;
734 int i, n, nl, nf;
735 CFid *fid;
737 if((fid = nsopen(factotum, nil, "ctl", OREAD)) == nil){
738 fprint(2, "ssh-agent: open factotum: %r\n");
739 return;
741 for(;;){
742 if((n = fsread(fid, buf, sizeof buf-1)) <= 0)
743 break;
744 buf[n] = 0;
745 nl = getfields(buf, line, nelem(line), 1, "\n");
746 for(i=0; i<nl; i++){
747 nf = tokenize(line[i], f, nelem(f));
748 if(nf == 0 || strcmp(f[0], "key") != 0)
749 continue;
750 p = find(f, nf, "proto");
751 if(p == nil)
752 continue;
753 s = find(f, nf, "service");
754 if(s == nil)
755 continue;
757 if(strcmp(p, "rsa") == 0 && strcmp(s, "ssh") == 0)
758 printrsa1(f, nf);
759 if(strcmp(p, "rsa") == 0 && strcmp(s, "ssh-rsa") == 0)
760 printkey("ssh-rsa", putrsa, f, nf);
761 if(strcmp(p, "dsa") == 0 && strcmp(s, "ssh-dss") == 0)
762 printkey("ssh-dss", putdsa, f, nf);
765 fsclose(fid);
766 threadexitsall(nil);
769 mpint*
770 rsaunpad(mpint *b)
772 int i, n;
773 uchar buf[2560];
775 n = (mpsignif(b)+7)/8;
776 if(n > sizeof buf){
777 werrstr("rsaunpad: too big");
778 return nil;
780 mptobe(b, buf, n, nil);
782 /* the initial zero has been eaten by the betomp -> mptobe sequence */
783 if(buf[0] != 2){
784 werrstr("rsaunpad: expected leading 2");
785 return nil;
787 for(i=1; i<n; i++)
788 if(buf[i]==0)
789 break;
790 return betomp(buf+i, n-i, nil);
793 void
794 mptoberjust(mpint *b, uchar *buf, int len)
796 int n;
798 n = mptobe(b, buf, len, nil);
799 assert(n >= 0);
800 if(n < len){
801 len -= n;
802 memmove(buf+len, buf, n);
803 memset(buf, 0, len);
807 static int
808 dorsa(Aconn *a, mpint *mod, mpint *exp, mpint *chal, uchar chalbuf[32])
810 AuthRpc *rpc;
811 char buf[4096], *p;
812 mpint *decr, *unpad;
814 USED(exp);
815 if((rpc = auth_allocrpc()) == nil){
816 fprint(2, "ssh-agent: auth_allocrpc: %r\n");
817 return -1;
819 snprint(buf, sizeof buf, "proto=rsa service=ssh role=decrypt n=%lB ek=%lB", mod, exp);
820 if(chatty)
821 fprint(2, "ssh-agent: start %s\n", buf);
822 if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){
823 fprint(2, "ssh-agent: auth 'start' failed: %r\n");
824 Die:
825 auth_freerpc(rpc);
826 return -1;
829 p = mptoa(chal, 16, nil, 0);
830 if(p == nil){
831 fprint(2, "ssh-agent: dorsa: mptoa: %r\n");
832 goto Die;
834 if(chatty)
835 fprint(2, "ssh-agent: challenge %B => %s\n", chal, p);
836 if(auth_rpc(rpc, "writehex", p, strlen(p)) != ARok){
837 fprint(2, "ssh-agent: dorsa: auth 'write': %r\n");
838 free(p);
839 goto Die;
841 free(p);
842 if(auth_rpc(rpc, "readhex", nil, 0) != ARok){
843 fprint(2, "ssh-agent: dorsa: auth 'read': %r\n");
844 goto Die;
846 decr = strtomp(rpc->arg, nil, 16, nil);
847 if(chatty)
848 fprint(2, "ssh-agent: response %s => %B\n", rpc->arg, decr);
849 if(decr == nil){
850 fprint(2, "ssh-agent: dorsa: strtomp: %r\n");
851 goto Die;
853 unpad = rsaunpad(decr);
854 if(chatty)
855 fprint(2, "ssh-agent: unpad %B => %B\n", decr, unpad);
856 if(unpad == nil){
857 fprint(2, "ssh-agent: dorsa: rsaunpad: %r\n");
858 mpfree(decr);
859 goto Die;
861 mpfree(decr);
862 mptoberjust(unpad, chalbuf, 32);
863 mpfree(unpad);
864 auth_freerpc(rpc);
865 return 0;
868 int
869 keysign(Msg *mkey, Msg *mdata, Msg *msig)
871 char *s;
872 AuthRpc *rpc;
873 RSApub *rsa;
874 DSApub *dsa;
875 char buf[4096];
876 uchar digest[SHA1dlen];
878 s = getstr(mkey);
879 if(strcmp(s, "ssh-rsa") == 0){
880 rsa = getrsapub(mkey);
881 if(rsa == nil)
882 return -1;
883 snprint(buf, sizeof buf, "proto=rsa service=ssh-rsa role=sign n=%lB ek=%lB",
884 rsa->n, rsa->ek);
885 rsapubfree(rsa);
886 }else if(strcmp(s, "ssh-dss") == 0){
887 dsa = getdsapub(mkey);
888 if(dsa == nil)
889 return -1;
890 snprint(buf, sizeof buf, "proto=dsa service=ssh-dss role=sign p=%lB q=%lB alpha=%lB key=%lB",
891 dsa->p, dsa->q, dsa->alpha, dsa->key);
892 dsapubfree(dsa);
893 }else{
894 fprint(2, "ssh-agent: cannot sign key type %s\n", s);
895 werrstr("unknown key type %s", s);
896 return -1;
899 if((rpc = auth_allocrpc()) == nil){
900 fprint(2, "ssh-agent: auth_allocrpc: %r\n");
901 return -1;
903 if(chatty)
904 fprint(2, "ssh-agent: start %s\n", buf);
905 if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){
906 fprint(2, "ssh-agent: auth 'start' failed: %r\n");
907 Die:
908 auth_freerpc(rpc);
909 return -1;
911 sha1(mdata->bp, mdata->ep-mdata->bp, digest, nil);
912 if(auth_rpc(rpc, "write", digest, SHA1dlen) != ARok){
913 fprint(2, "ssh-agent: auth 'write in sign failed: %r\n");
914 goto Die;
916 if(auth_rpc(rpc, "read", nil, 0) != ARok){
917 fprint(2, "ssh-agent: auth 'read' failed: %r\n");
918 goto Die;
920 newmsg(msig);
921 putstr(msig, s);
922 put4(msig, rpc->narg);
923 putn(msig, rpc->arg, rpc->narg);
924 auth_freerpc(rpc);
925 return 0;
928 int
929 runmsg(Aconn *a)
931 char *p;
932 int n, nk, type, rt, vers;
933 mpint *ek, *mod, *chal;
934 uchar sessid[16], chalbuf[32], digest[MD5dlen];
935 uint len, flags;
936 DigestState *s;
937 Msg m, mkey, mdata, msig;
939 if(a->ndata < 4)
940 return 0;
941 len = (a->data[0]<<24)|(a->data[1]<<16)|(a->data[2]<<8)|a->data[3];
942 if(a->ndata < 4+len)
943 return 0;
944 m.p = a->data+4;
945 m.ep = m.p+len;
946 type = get1(&m);
947 if(chatty)
948 fprint(2, "msg %d: %.*H\n", type, len, m.p);
949 switch(type){
950 default:
951 Failure:
952 newreply(&m, SSH_AGENT_FAILURE);
953 reply(a, &m);
954 break;
956 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
957 vers = 1;
958 newreply(&m, SSH_AGENT_RSA_IDENTITIES_ANSWER);
959 goto Identities;
960 case SSH2_AGENTC_REQUEST_IDENTITIES:
961 vers = 2;
962 newreply(&m, SSH2_AGENT_IDENTITIES_ANSWER);
963 Identities:
964 nk = listkeys(&m, vers);
965 if(nk < 0){
966 mreset(&m);
967 goto Failure;
969 if(chatty)
970 fprint(2, "request identities\n", nk);
971 reply(a, &m);
972 break;
974 case SSH_AGENTC_RSA_CHALLENGE:
975 n = get4(&m);
976 ek = getmp(&m);
977 mod = getmp(&m);
978 chal = getmp(&m);
979 if((p = (char*)getn(&m, 16)) == nil){
980 Failchal:
981 mpfree(ek);
982 mpfree(mod);
983 mpfree(chal);
984 goto Failure;
986 memmove(sessid, p, 16);
987 rt = get4(&m);
988 if(rt != 1 || dorsa(a, mod, ek, chal, chalbuf) < 0)
989 goto Failchal;
990 s = md5(chalbuf, 32, nil, nil);
991 if(s == nil)
992 goto Failchal;
993 md5(sessid, 16, digest, s);
994 print("md5 %.*H %.*H => %.*H\n", 32, chalbuf, 16, sessid, MD5dlen, digest);
996 newreply(&m, SSH_AGENT_RSA_RESPONSE);
997 putn(&m, digest, 16);
998 reply(a, &m);
1000 mpfree(ek);
1001 mpfree(mod);
1002 mpfree(chal);
1003 break;
1005 case SSH2_AGENTC_SIGN_REQUEST:
1006 if(getm(&m, &mkey) == nil
1007 || getm(&m, &mdata) == nil)
1008 goto Failure;
1009 flags = get4(&m);
1010 if(flags & SSH_AGENT_OLD_SIGNATURE)
1011 goto Failure;
1012 if(keysign(&mkey, &mdata, &msig) < 0)
1013 goto Failure;
1014 if(chatty)
1015 fprint(2, "signature: %.*H\n",
1016 msig.p-msig.bp, msig.bp);
1017 newreply(&m, SSH2_AGENT_SIGN_RESPONSE);
1018 putm(&m, &msig);
1019 mreset(&msig);
1020 reply(a, &m);
1021 break;
1023 case SSH_AGENTC_ADD_RSA_IDENTITY:
1025 msg: n[4] mod[mp] pubexp[exp] privexp[mp]
1026 p^-1 mod q[mp] p[mp] q[mp] comment[str]
1028 goto Failure;
1030 case SSH_AGENTC_REMOVE_RSA_IDENTITY:
1032 msg: n[4] mod[mp] pubexp[mp]
1034 goto Failure;
1038 a->ndata -= 4+len;
1039 memmove(a->data, a->data+4+len, a->ndata);
1040 return 1;
1043 void*
1044 emalloc(int n)
1046 void *v;
1048 v = mallocz(n, 1);
1049 if(v == nil){
1050 abort();
1051 sysfatal("out of memory allocating %d", n);
1053 return v;
1056 void*
1057 erealloc(void *v, int n)
1059 v = realloc(v, n);
1060 if(v == nil){
1061 abort();
1062 sysfatal("out of memory reallocating %d", n);
1064 return v;