ssh-agent.c (18364B)
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> 11 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, 28 29 SSH2_AGENTC_REQUEST_IDENTITIES = 11, 30 SSH2_AGENT_IDENTITIES_ANSWER, 31 SSH2_AGENTC_SIGN_REQUEST, 32 SSH2_AGENT_SIGN_RESPONSE, 33 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, 39 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, 45 46 SSH_AGENT_CONSTRAIN_LIFETIME = 1, 47 SSH_AGENT_CONSTRAIN_CONFIRM = 2, 48 49 SSH2_AGENT_FAILURE = 30, 50 51 SSH_COM_AGENT2_FAILURE = 102, 52 SSH_AGENT_OLD_SIGNATURE = 0x01 53 }; 54 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 }; 64 65 typedef struct Msg Msg; 66 struct Msg 67 { 68 uchar *bp; 69 uchar *p; 70 uchar *ep; 71 int bpalloc; 72 }; 73 74 char adir[40]; 75 int afd; 76 int chatty; 77 char *factotum = "factotum"; 78 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); 85 86 void 87 usage(void) 88 { 89 fprint(2, "usage: 9 ssh-agent [-D] [factotum]\n"); 90 threadexitsall("usage"); 91 } 92 93 int 94 threadmaybackground(void) 95 { 96 return 1; 97 } 98 99 void 100 threadmain(int argc, char **argv) 101 { 102 int fd, pid, export, dotextlist; 103 char dir[100], *ns; 104 char sock[200], addr[200]; 105 uvlong x; 106 107 export = 0; 108 dotextlist = 0; 109 pid = getpid(); 110 fmtinstall('B', mpfmt); 111 fmtinstall('H', encodefmt); 112 fmtinstall('[', encodefmt); 113 114 ARGBEGIN{ 115 case '9': 116 chatty9pclient++; 117 break; 118 case 'D': 119 chatty++; 120 break; 121 case 'e': 122 export = 1; 123 break; 124 case 'l': 125 dotextlist = 1; 126 break; 127 default: 128 usage(); 129 }ARGEND 130 131 if(argc > 1) 132 usage(); 133 if(argc == 1) 134 factotum = argv[0]; 135 136 if(dotextlist) 137 listkeystext(); 138 139 ns = getns(); 140 snprint(sock, sizeof sock, "%s/ssh-agent.socket", ns); 141 if(0){ 142 x = ((uvlong)fastrand()<<32) | fastrand(); 143 x ^= ((uvlong)fastrand()<<32) | fastrand(); 144 snprint(dir, sizeof dir, "/tmp/ssh-%llux", x); 145 if((fd = create(dir, OREAD, DMDIR|0700)) < 0) 146 sysfatal("mkdir %s: %r", dir); 147 close(fd); 148 snprint(sock, sizeof sock, "%s/agent.%d", dir, pid); 149 } 150 snprint(addr, sizeof addr, "unix!%s", sock); 151 152 if((afd = announce(addr, adir)) < 0) 153 sysfatal("announce %s: %r", addr); 154 155 print("SSH_AUTH_SOCK=%s;\n", sock); 156 if(export) 157 print("export SSH_AUTH_SOCK;\n"); 158 print("SSH_AGENT_PID=%d;\n", pid); 159 if(export) 160 print("export SSH_AGENT_PID;\n"); 161 close(1); 162 rfork(RFNOTEG); 163 proccreate(listenproc, nil, STACK); 164 threadexits(0); 165 } 166 167 void 168 listenproc(void *v) 169 { 170 Aconn *a; 171 172 USED(v); 173 for(;;){ 174 a = emalloc(sizeof *a); 175 a->ctl = listen(adir, a->dir); 176 if(a->ctl < 0) 177 sysfatal("listen: %r"); 178 proccreate(agentproc, a, STACK); 179 } 180 } 181 182 void 183 agentproc(void *v) 184 { 185 Aconn *a; 186 int n; 187 188 a = v; 189 a->fd = accept(a->ctl, a->dir); 190 close(a->ctl); 191 a->ctl = -1; 192 for(;;){ 193 a->data = erealloc(a->data, a->ndata+1024); 194 n = read(a->fd, a->data+a->ndata, 1024); 195 if(n <= 0) 196 break; 197 a->ndata += n; 198 while(runmsg(a)) 199 ; 200 } 201 close(a->fd); 202 free(a); 203 threadexits(nil); 204 } 205 206 int 207 get1(Msg *m) 208 { 209 if(m->p >= m->ep) 210 return 0; 211 return *m->p++; 212 } 213 214 int 215 get2(Msg *m) 216 { 217 uint x; 218 219 if(m->p+2 > m->ep) 220 return 0; 221 x = (m->p[0]<<8)|m->p[1]; 222 m->p += 2; 223 return x; 224 } 225 226 int 227 get4(Msg *m) 228 { 229 uint x; 230 if(m->p+4 > m->ep) 231 return 0; 232 x = (m->p[0]<<24)|(m->p[1]<<16)|(m->p[2]<<8)|m->p[3]; 233 m->p += 4; 234 return x; 235 } 236 237 uchar* 238 getn(Msg *m, uint n) 239 { 240 uchar *p; 241 242 if(m->p+n > m->ep) 243 return nil; 244 p = m->p; 245 m->p += n; 246 return p; 247 } 248 249 char* 250 getstr(Msg *m) 251 { 252 uint n; 253 uchar *p; 254 255 n = get4(m); 256 p = getn(m, n); 257 if(p == nil) 258 return nil; 259 p--; 260 memmove(p, p+1, n); 261 p[n] = 0; 262 return (char*)p; 263 } 264 265 mpint* 266 getmp(Msg *m) 267 { 268 int n; 269 uchar *p; 270 271 n = (get2(m)+7)/8; 272 if((p=getn(m, n)) == nil) 273 return nil; 274 return betomp(p, n, nil); 275 } 276 277 mpint* 278 getmp2(Msg *m) 279 { 280 int n; 281 uchar *p; 282 283 n = get4(m); 284 if((p = getn(m, n)) == nil) 285 return nil; 286 return betomp(p, n, nil); 287 } 288 289 void 290 newmsg(Msg *m) 291 { 292 memset(m, 0, sizeof *m); 293 } 294 295 void 296 mreset(Msg *m) 297 { 298 if(m->bpalloc){ 299 memset(m->bp, 0, m->ep-m->bp); 300 free(m->bp); 301 } 302 memset(m, 0, sizeof *m); 303 } 304 305 Msg* 306 getm(Msg *m, Msg *mm) 307 { 308 uint n; 309 uchar *p; 310 311 n = get4(m); 312 if((p = getn(m, n)) == nil) 313 return nil; 314 mm->bp = p; 315 mm->p = p; 316 mm->ep = p+n; 317 mm->bpalloc = 0; 318 return mm; 319 } 320 321 uchar* 322 ensure(Msg *m, int n) 323 { 324 int len; 325 uchar *p; 326 uchar *obp; 327 328 if(m->bp == nil) 329 m->bpalloc = 1; 330 if(!m->bpalloc){ 331 p = emalloc(m->ep - m->bp); 332 memmove(p, m->bp, m->ep - m->bp); 333 obp = m->bp; 334 m->bp = p; 335 m->ep += m->bp - obp; 336 m->p += m->bp - obp; 337 m->bpalloc = 1; 338 } 339 len = m->ep - m->bp; 340 if(m->p+n > m->ep){ 341 obp = m->bp; 342 m->bp = erealloc(m->bp, len+n+1024); 343 m->p += m->bp - obp; 344 m->ep += m->bp - obp; 345 m->ep += n+1024; 346 } 347 p = m->p; 348 m->p += n; 349 return p; 350 } 351 352 void 353 put4(Msg *m, uint n) 354 { 355 uchar *p; 356 357 p = ensure(m, 4); 358 p[0] = (n>>24)&0xFF; 359 p[1] = (n>>16)&0xFF; 360 p[2] = (n>>8)&0xFF; 361 p[3] = n&0xFF; 362 } 363 364 void 365 put2(Msg *m, uint n) 366 { 367 uchar *p; 368 369 p = ensure(m, 2); 370 p[0] = (n>>8)&0xFF; 371 p[1] = n&0xFF; 372 } 373 374 void 375 put1(Msg *m, uint n) 376 { 377 uchar *p; 378 379 p = ensure(m, 1); 380 p[0] = n&0xFF; 381 } 382 383 void 384 putn(Msg *m, void *a, uint n) 385 { 386 uchar *p; 387 388 p = ensure(m, n); 389 memmove(p, a, n); 390 } 391 392 void 393 putmp(Msg *m, mpint *b) 394 { 395 int bits, n; 396 uchar *p; 397 398 bits = mpsignif(b); 399 put2(m, bits); 400 n = (bits+7)/8; 401 p = ensure(m, n); 402 mptobe(b, p, n, nil); 403 } 404 405 void 406 putmp2(Msg *m, mpint *b) 407 { 408 int bits, n; 409 uchar *p; 410 411 if(mpcmp(b, mpzero) == 0){ 412 put4(m, 0); 413 return; 414 } 415 bits = mpsignif(b); 416 n = (bits+7)/8; 417 if(bits%8 == 0){ 418 put4(m, n+1); 419 put1(m, 0); 420 }else 421 put4(m, n); 422 p = ensure(m, n); 423 mptobe(b, p, n, nil); 424 } 425 426 void 427 putstr(Msg *m, char *s) 428 { 429 int n; 430 431 n = strlen(s); 432 put4(m, n); 433 putn(m, s, n); 434 } 435 436 void 437 putm(Msg *m, Msg *mm) 438 { 439 uint n; 440 441 n = mm->p - mm->bp; 442 put4(m, n); 443 putn(m, mm->bp, n); 444 } 445 446 void 447 newreply(Msg *m, int type) 448 { 449 memset(m, 0, sizeof *m); 450 put4(m, 0); 451 put1(m, type); 452 } 453 454 void 455 reply(Aconn *a, Msg *m) 456 { 457 uint n; 458 uchar *p; 459 460 n = (m->p - m->bp) - 4; 461 p = m->bp; 462 p[0] = (n>>24)&0xFF; 463 p[1] = (n>>16)&0xFF; 464 p[2] = (n>>8)&0xFF; 465 p[3] = n&0xFF; 466 if(chatty) 467 fprint(2, "respond %d t=%d: %.*H\n", n, p[4], n, m->bp+4); 468 write(a->fd, p, n+4); 469 mreset(m); 470 } 471 472 typedef struct Key Key; 473 struct Key 474 { 475 mpint *mod; 476 mpint *ek; 477 char *comment; 478 }; 479 480 static char* 481 find(char **f, int nf, char *k) 482 { 483 int i, len; 484 485 len = strlen(k); 486 for(i=1; i<nf; i++) /* i=1: f[0] is "key" */ 487 if(strncmp(f[i], k, len) == 0 && f[i][len] == '=') 488 return f[i]+len+1; 489 return nil; 490 } 491 492 static int 493 putrsa1(Msg *m, char **f, int nf) 494 { 495 char *p; 496 mpint *mod, *ek; 497 498 p = find(f, nf, "n"); 499 if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil) 500 return -1; 501 p = find(f, nf, "ek"); 502 if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){ 503 mpfree(mod); 504 return -1; 505 } 506 p = find(f, nf, "comment"); 507 if(p == nil) 508 p = ""; 509 put4(m, mpsignif(mod)); 510 putmp(m, ek); 511 putmp(m, mod); 512 putstr(m, p); 513 mpfree(mod); 514 mpfree(ek); 515 return 0; 516 } 517 518 void 519 printattr(char **f, int nf) 520 { 521 int i; 522 523 print("#"); 524 for(i=0; i<nf; i++) 525 print(" %s", f[i]); 526 print("\n"); 527 } 528 529 void 530 printrsa1(char **f, int nf) 531 { 532 char *p; 533 mpint *mod, *ek; 534 535 p = find(f, nf, "n"); 536 if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil) 537 return; 538 p = find(f, nf, "ek"); 539 if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){ 540 mpfree(mod); 541 return; 542 } 543 p = find(f, nf, "comment"); 544 if(p == nil) 545 p = ""; 546 547 if(chatty) 548 printattr(f, nf); 549 print("%d %.10B %.10B %s\n", mpsignif(mod), ek, mod, p); 550 mpfree(ek); 551 mpfree(mod); 552 } 553 554 static int 555 putrsa(Msg *m, char **f, int nf) 556 { 557 char *p; 558 mpint *mod, *ek; 559 560 p = find(f, nf, "n"); 561 if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil) 562 return -1; 563 p = find(f, nf, "ek"); 564 if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){ 565 mpfree(mod); 566 return -1; 567 } 568 putstr(m, "ssh-rsa"); 569 putmp2(m, ek); 570 putmp2(m, mod); 571 mpfree(ek); 572 mpfree(mod); 573 return 0; 574 } 575 576 RSApub* 577 getrsapub(Msg *m) 578 { 579 RSApub *k; 580 581 k = rsapuballoc(); 582 if(k == nil) 583 return nil; 584 k->ek = getmp2(m); 585 k->n = getmp2(m); 586 if(k->ek == nil || k->n == nil){ 587 rsapubfree(k); 588 return nil; 589 } 590 return k; 591 } 592 593 static int 594 putdsa(Msg *m, char **f, int nf) 595 { 596 char *p; 597 int ret; 598 mpint *dp, *dq, *dalpha, *dkey; 599 600 ret = -1; 601 dp = dq = dalpha = dkey = nil; 602 p = find(f, nf, "p"); 603 if(p == nil || (dp = strtomp(p, nil, 16, nil)) == nil) 604 goto out; 605 p = find(f, nf, "q"); 606 if(p == nil || (dq = strtomp(p, nil, 16, nil)) == nil) 607 goto out; 608 p = find(f, nf, "alpha"); 609 if(p == nil || (dalpha = strtomp(p, nil, 16, nil)) == nil) 610 goto out; 611 p = find(f, nf, "key"); 612 if(p == nil || (dkey = strtomp(p, nil, 16, nil)) == nil) 613 goto out; 614 putstr(m, "ssh-dss"); 615 putmp2(m, dp); 616 putmp2(m, dq); 617 putmp2(m, dalpha); 618 putmp2(m, dkey); 619 ret = 0; 620 out: 621 mpfree(dp); 622 mpfree(dq); 623 mpfree(dalpha); 624 mpfree(dkey); 625 return ret; 626 } 627 628 static int 629 putkey2(Msg *m, int (*put)(Msg*,char**,int), char **f, int nf) 630 { 631 char *p; 632 Msg mm; 633 634 newmsg(&mm); 635 if(put(&mm, f, nf) < 0) 636 return -1; 637 putm(m, &mm); 638 mreset(&mm); 639 p = find(f, nf, "comment"); 640 if(p == nil) 641 p = ""; 642 putstr(m, p); 643 return 0; 644 } 645 646 static int 647 printkey(char *type, int (*put)(Msg*,char**,int), char **f, int nf) 648 { 649 Msg m; 650 char *p; 651 652 newmsg(&m); 653 if(put(&m, f, nf) < 0) 654 return -1; 655 p = find(f, nf, "comment"); 656 if(p == nil) 657 p = ""; 658 if(chatty) 659 printattr(f, nf); 660 print("%s %.*[ %s\n", type, m.p-m.bp, m.bp, p); 661 mreset(&m); 662 return 0; 663 } 664 665 DSApub* 666 getdsapub(Msg *m) 667 { 668 DSApub *k; 669 670 k = dsapuballoc(); 671 if(k == nil) 672 return nil; 673 k->p = getmp2(m); 674 k->q = getmp2(m); 675 k->alpha = getmp2(m); 676 k->key = getmp2(m); 677 if(!k->p || !k->q || !k->alpha || !k->key){ 678 dsapubfree(k); 679 return nil; 680 } 681 return k; 682 } 683 684 static int 685 listkeys(Msg *m, int version) 686 { 687 char buf[8192+1], *line[100], *f[20], *p, *s; 688 int pnk; 689 int i, n, nl, nf, nk; 690 CFid *fid; 691 692 nk = 0; 693 pnk = m->p - m->bp; 694 put4(m, 0); 695 if((fid = nsopen(factotum, nil, "ctl", OREAD)) == nil){ 696 fprint(2, "ssh-agent: open factotum: %r\n"); 697 return -1; 698 } 699 for(;;){ 700 if((n = fsread(fid, buf, sizeof buf-1)) <= 0) 701 break; 702 buf[n] = 0; 703 nl = getfields(buf, line, nelem(line), 1, "\n"); 704 for(i=0; i<nl; i++){ 705 nf = tokenize(line[i], f, nelem(f)); 706 if(nf == 0 || strcmp(f[0], "key") != 0) 707 continue; 708 p = find(f, nf, "proto"); 709 if(p == nil) 710 continue; 711 s = find(f, nf, "service"); 712 if(s == nil) 713 continue; 714 715 if(version == 1 && strcmp(p, "rsa") == 0 && strcmp(s, "ssh") == 0) 716 if(putrsa1(m, f, nf) >= 0) 717 nk++; 718 if(version == 2 && strcmp(p, "rsa") == 0 && strcmp(s, "ssh-rsa") == 0) 719 if(putkey2(m, putrsa, f, nf) >= 0) 720 nk++; 721 if(version == 2 && strcmp(p, "dsa") == 0 && strcmp(s, "ssh-dss") == 0) 722 if(putkey2(m, putdsa, f, nf) >= 0) 723 nk++; 724 } 725 } 726 if(chatty) 727 fprint(2, "sending %d keys\n", nk); 728 fsclose(fid); 729 m->bp[pnk+0] = (nk>>24)&0xFF; 730 m->bp[pnk+1] = (nk>>16)&0xFF; 731 m->bp[pnk+2] = (nk>>8)&0xFF; 732 m->bp[pnk+3] = nk&0xFF; 733 return nk; 734 } 735 736 void 737 listkeystext(void) 738 { 739 char buf[8192+1], *line[100], *f[20], *p, *s; 740 int i, n, nl, nf; 741 CFid *fid; 742 743 if((fid = nsopen(factotum, nil, "ctl", OREAD)) == nil){ 744 fprint(2, "ssh-agent: open factotum: %r\n"); 745 return; 746 } 747 for(;;){ 748 if((n = fsread(fid, buf, sizeof buf-1)) <= 0) 749 break; 750 buf[n] = 0; 751 nl = getfields(buf, line, nelem(line), 1, "\n"); 752 for(i=0; i<nl; i++){ 753 nf = tokenize(line[i], f, nelem(f)); 754 if(nf == 0 || strcmp(f[0], "key") != 0) 755 continue; 756 p = find(f, nf, "proto"); 757 if(p == nil) 758 continue; 759 s = find(f, nf, "service"); 760 if(s == nil) 761 continue; 762 763 if(strcmp(p, "rsa") == 0 && strcmp(s, "ssh") == 0) 764 printrsa1(f, nf); 765 if(strcmp(p, "rsa") == 0 && strcmp(s, "ssh-rsa") == 0) 766 printkey("ssh-rsa", putrsa, f, nf); 767 if(strcmp(p, "dsa") == 0 && strcmp(s, "ssh-dss") == 0) 768 printkey("ssh-dss", putdsa, f, nf); 769 } 770 } 771 fsclose(fid); 772 threadexitsall(nil); 773 } 774 775 mpint* 776 rsaunpad(mpint *b) 777 { 778 int i, n; 779 uchar buf[2560]; 780 781 n = (mpsignif(b)+7)/8; 782 if(n > sizeof buf){ 783 werrstr("rsaunpad: too big"); 784 return nil; 785 } 786 mptobe(b, buf, n, nil); 787 788 /* the initial zero has been eaten by the betomp -> mptobe sequence */ 789 if(buf[0] != 2){ 790 werrstr("rsaunpad: expected leading 2"); 791 return nil; 792 } 793 for(i=1; i<n; i++) 794 if(buf[i]==0) 795 break; 796 return betomp(buf+i, n-i, nil); 797 } 798 799 void 800 mptoberjust(mpint *b, uchar *buf, int len) 801 { 802 int n; 803 804 n = mptobe(b, buf, len, nil); 805 assert(n >= 0); 806 if(n < len){ 807 len -= n; 808 memmove(buf+len, buf, n); 809 memset(buf, 0, len); 810 } 811 } 812 813 static int 814 dorsa(Aconn *a, mpint *mod, mpint *exp, mpint *chal, uchar chalbuf[32]) 815 { 816 AuthRpc *rpc; 817 char buf[4096], *p; 818 mpint *decr, *unpad; 819 820 USED(exp); 821 if((rpc = auth_allocrpc()) == nil){ 822 fprint(2, "ssh-agent: auth_allocrpc: %r\n"); 823 return -1; 824 } 825 snprint(buf, sizeof buf, "proto=rsa service=ssh role=decrypt n=%lB ek=%lB", mod, exp); 826 if(chatty) 827 fprint(2, "ssh-agent: start %s\n", buf); 828 if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){ 829 fprint(2, "ssh-agent: auth 'start' failed: %r\n"); 830 Die: 831 auth_freerpc(rpc); 832 return -1; 833 } 834 835 p = mptoa(chal, 16, nil, 0); 836 if(p == nil){ 837 fprint(2, "ssh-agent: dorsa: mptoa: %r\n"); 838 goto Die; 839 } 840 if(chatty) 841 fprint(2, "ssh-agent: challenge %B => %s\n", chal, p); 842 if(auth_rpc(rpc, "writehex", p, strlen(p)) != ARok){ 843 fprint(2, "ssh-agent: dorsa: auth 'write': %r\n"); 844 free(p); 845 goto Die; 846 } 847 free(p); 848 if(auth_rpc(rpc, "readhex", nil, 0) != ARok){ 849 fprint(2, "ssh-agent: dorsa: auth 'read': %r\n"); 850 goto Die; 851 } 852 decr = strtomp(rpc->arg, nil, 16, nil); 853 if(chatty) 854 fprint(2, "ssh-agent: response %s => %B\n", rpc->arg, decr); 855 if(decr == nil){ 856 fprint(2, "ssh-agent: dorsa: strtomp: %r\n"); 857 goto Die; 858 } 859 unpad = rsaunpad(decr); 860 if(chatty) 861 fprint(2, "ssh-agent: unpad %B => %B\n", decr, unpad); 862 if(unpad == nil){ 863 fprint(2, "ssh-agent: dorsa: rsaunpad: %r\n"); 864 mpfree(decr); 865 goto Die; 866 } 867 mpfree(decr); 868 mptoberjust(unpad, chalbuf, 32); 869 mpfree(unpad); 870 auth_freerpc(rpc); 871 return 0; 872 } 873 874 int 875 keysign(Msg *mkey, Msg *mdata, Msg *msig) 876 { 877 char *s; 878 AuthRpc *rpc; 879 RSApub *rsa; 880 DSApub *dsa; 881 char buf[4096]; 882 uchar digest[SHA1dlen]; 883 884 s = getstr(mkey); 885 if(strcmp(s, "ssh-rsa") == 0){ 886 rsa = getrsapub(mkey); 887 if(rsa == nil) 888 return -1; 889 snprint(buf, sizeof buf, "proto=rsa service=ssh-rsa role=sign n=%lB ek=%lB", 890 rsa->n, rsa->ek); 891 rsapubfree(rsa); 892 }else if(strcmp(s, "ssh-dss") == 0){ 893 dsa = getdsapub(mkey); 894 if(dsa == nil) 895 return -1; 896 snprint(buf, sizeof buf, "proto=dsa service=ssh-dss role=sign p=%lB q=%lB alpha=%lB key=%lB", 897 dsa->p, dsa->q, dsa->alpha, dsa->key); 898 dsapubfree(dsa); 899 }else{ 900 fprint(2, "ssh-agent: cannot sign key type %s\n", s); 901 werrstr("unknown key type %s", s); 902 return -1; 903 } 904 905 if((rpc = auth_allocrpc()) == nil){ 906 fprint(2, "ssh-agent: auth_allocrpc: %r\n"); 907 return -1; 908 } 909 if(chatty) 910 fprint(2, "ssh-agent: start %s\n", buf); 911 if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){ 912 fprint(2, "ssh-agent: auth 'start' failed: %r\n"); 913 Die: 914 auth_freerpc(rpc); 915 return -1; 916 } 917 sha1(mdata->bp, mdata->ep-mdata->bp, digest, nil); 918 if(auth_rpc(rpc, "write", digest, SHA1dlen) != ARok){ 919 fprint(2, "ssh-agent: auth 'write in sign failed: %r\n"); 920 goto Die; 921 } 922 if(auth_rpc(rpc, "read", nil, 0) != ARok){ 923 fprint(2, "ssh-agent: auth 'read' failed: %r\n"); 924 goto Die; 925 } 926 newmsg(msig); 927 putstr(msig, s); 928 put4(msig, rpc->narg); 929 putn(msig, rpc->arg, rpc->narg); 930 auth_freerpc(rpc); 931 return 0; 932 } 933 934 int 935 runmsg(Aconn *a) 936 { 937 char *p; 938 int n, nk, type, rt, vers; 939 mpint *ek, *mod, *chal; 940 uchar sessid[16], chalbuf[32], digest[MD5dlen]; 941 uint len, flags; 942 DigestState *s; 943 Msg m, mkey, mdata, msig; 944 945 if(a->ndata < 4) 946 return 0; 947 len = (a->data[0]<<24)|(a->data[1]<<16)|(a->data[2]<<8)|a->data[3]; 948 if(a->ndata < 4+len) 949 return 0; 950 m.p = a->data+4; 951 m.ep = m.p+len; 952 type = get1(&m); 953 if(chatty) 954 fprint(2, "msg %d: %.*H\n", type, len, m.p); 955 switch(type){ 956 default: 957 Failure: 958 newreply(&m, SSH_AGENT_FAILURE); 959 reply(a, &m); 960 break; 961 962 case SSH_AGENTC_REQUEST_RSA_IDENTITIES: 963 vers = 1; 964 newreply(&m, SSH_AGENT_RSA_IDENTITIES_ANSWER); 965 goto Identities; 966 case SSH2_AGENTC_REQUEST_IDENTITIES: 967 vers = 2; 968 newreply(&m, SSH2_AGENT_IDENTITIES_ANSWER); 969 Identities: 970 nk = listkeys(&m, vers); 971 if(nk < 0){ 972 mreset(&m); 973 goto Failure; 974 } 975 if(chatty) 976 fprint(2, "request identities\n", nk); 977 reply(a, &m); 978 break; 979 980 case SSH_AGENTC_RSA_CHALLENGE: 981 n = get4(&m); 982 USED(n); 983 ek = getmp(&m); 984 mod = getmp(&m); 985 chal = getmp(&m); 986 if((p = (char*)getn(&m, 16)) == nil){ 987 Failchal: 988 mpfree(ek); 989 mpfree(mod); 990 mpfree(chal); 991 goto Failure; 992 } 993 memmove(sessid, p, 16); 994 rt = get4(&m); 995 if(rt != 1 || dorsa(a, mod, ek, chal, chalbuf) < 0) 996 goto Failchal; 997 s = md5(chalbuf, 32, nil, nil); 998 if(s == nil) 999 goto Failchal; 1000 md5(sessid, 16, digest, s); 1001 print("md5 %.*H %.*H => %.*H\n", 32, chalbuf, 16, sessid, MD5dlen, digest); 1002 1003 newreply(&m, SSH_AGENT_RSA_RESPONSE); 1004 putn(&m, digest, 16); 1005 reply(a, &m); 1006 1007 mpfree(ek); 1008 mpfree(mod); 1009 mpfree(chal); 1010 break; 1011 1012 case SSH2_AGENTC_SIGN_REQUEST: 1013 if(getm(&m, &mkey) == nil 1014 || getm(&m, &mdata) == nil) 1015 goto Failure; 1016 flags = get4(&m); 1017 if(flags & SSH_AGENT_OLD_SIGNATURE) 1018 goto Failure; 1019 if(keysign(&mkey, &mdata, &msig) < 0) 1020 goto Failure; 1021 if(chatty) 1022 fprint(2, "signature: %.*H\n", 1023 msig.p-msig.bp, msig.bp); 1024 newreply(&m, SSH2_AGENT_SIGN_RESPONSE); 1025 putm(&m, &msig); 1026 mreset(&msig); 1027 reply(a, &m); 1028 break; 1029 1030 case SSH_AGENTC_ADD_RSA_IDENTITY: 1031 /* 1032 msg: n[4] mod[mp] pubexp[exp] privexp[mp] 1033 p^-1 mod q[mp] p[mp] q[mp] comment[str] 1034 */ 1035 goto Failure; 1036 1037 case SSH_AGENTC_REMOVE_RSA_IDENTITY: 1038 /* 1039 msg: n[4] mod[mp] pubexp[mp] 1040 */ 1041 goto Failure; 1042 1043 } 1044 1045 a->ndata -= 4+len; 1046 memmove(a->data, a->data+4+len, a->ndata); 1047 return 1; 1048 } 1049 1050 void* 1051 emalloc(int n) 1052 { 1053 void *v; 1054 1055 v = mallocz(n, 1); 1056 if(v == nil){ 1057 abort(); 1058 sysfatal("out of memory allocating %d", n); 1059 } 1060 return v; 1061 } 1062 1063 void* 1064 erealloc(void *v, int n) 1065 { 1066 v = realloc(v, n); 1067 if(v == nil){ 1068 abort(); 1069 sysfatal("out of memory reallocating %d", n); 1070 } 1071 return v; 1072 }