agent.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. #include "ssh.h"
  2. #include <bio.h>
  3. typedef struct Key Key;
  4. struct Key
  5. {
  6. mpint *mod;
  7. mpint *ek;
  8. char *comment;
  9. };
  10. typedef struct Achan Achan;
  11. struct Achan
  12. {
  13. int open;
  14. u32int chan; /* of remote */
  15. uchar lbuf[4];
  16. uint nlbuf;
  17. uint len;
  18. uchar *data;
  19. int ndata;
  20. int needeof;
  21. int needclosed;
  22. };
  23. Achan achan[16];
  24. static char*
  25. find(char **f, int nf, char *k)
  26. {
  27. int i, len;
  28. len = strlen(k);
  29. for(i=1; i<nf; i++) /* i=1: f[0] is "key" */
  30. if(strncmp(f[i], k, len) == 0 && f[i][len] == '=')
  31. return f[i]+len+1;
  32. return nil;
  33. }
  34. static int
  35. listkeys(Key **kp)
  36. {
  37. Biobuf *b;
  38. Key *k;
  39. int nk;
  40. char *p, *f[20];
  41. int nf;
  42. mpint *mod, *ek;
  43. *kp = nil;
  44. if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil)
  45. return -1;
  46. k = nil;
  47. nk = 0;
  48. while((p = Brdline(b, '\n')) != nil){
  49. p[Blinelen(b)-1] = '\0';
  50. nf = tokenize(p, f, nelem(f));
  51. if(nf == 0 || strcmp(f[0], "key") != 0)
  52. continue;
  53. p = find(f, nf, "proto");
  54. if(p == nil || strcmp(p, "sshrsa") != 0)
  55. continue;
  56. p = find(f, nf, "n");
  57. if(p == nil || (mod = strtomp(p, nil, 16, nil)) == nil)
  58. continue;
  59. p = find(f, nf, "ek");
  60. if(p == nil || (ek = strtomp(p, nil, 16, nil)) == nil){
  61. mpfree(mod);
  62. continue;
  63. }
  64. p = find(f, nf, "comment");
  65. if(p == nil)
  66. p = "";
  67. k = erealloc(k, (nk+1)*sizeof(k[0]));
  68. k[nk].mod = mod;
  69. k[nk].ek = ek;
  70. k[nk].comment = emalloc(strlen(p)+1);
  71. strcpy(k[nk].comment, p);
  72. nk++;
  73. }
  74. Bterm(b);
  75. *kp = k;
  76. return nk;
  77. }
  78. static int
  79. dorsa(mpint *mod, mpint *exp, mpint *chal, uchar chalbuf[32])
  80. {
  81. int afd;
  82. AuthRpc *rpc;
  83. mpint *m;
  84. char buf[4096], *p;
  85. mpint *decr, *unpad;
  86. USED(exp);
  87. snprint(buf, sizeof buf, "proto=sshrsa role=client");
  88. if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){
  89. debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n");
  90. return -1;
  91. }
  92. if((rpc = auth_allocrpc(afd)) == nil){
  93. debug(DBG_AUTH, "auth_allocrpc: %r\n");
  94. close(afd);
  95. return -1;
  96. }
  97. if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){
  98. debug(DBG_AUTH, "auth_rpc start failed: %r\n");
  99. Die:
  100. auth_freerpc(rpc);
  101. close(afd);
  102. return -1;
  103. }
  104. m = nil;
  105. debug(DBG_AUTH, "trying factotum rsa keys\n");
  106. while(auth_rpc(rpc, "read", nil, 0) == ARok){
  107. debug(DBG_AUTH, "try %s\n", (char*)rpc->arg);
  108. m = strtomp(rpc->arg, nil, 16, nil);
  109. if(mpcmp(m, mod) == 0)
  110. break;
  111. mpfree(m);
  112. m = nil;
  113. }
  114. if(m == nil)
  115. goto Die;
  116. mpfree(m);
  117. p = mptoa(chal, 16, nil, 0);
  118. if(p == nil){
  119. debug(DBG_AUTH, "\tmptoa failed: %r\n");
  120. goto Die;
  121. }
  122. if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){
  123. debug(DBG_AUTH, "\tauth_rpc write failed: %r\n");
  124. free(p);
  125. goto Die;
  126. }
  127. free(p);
  128. if(auth_rpc(rpc, "read", nil, 0) != ARok){
  129. debug(DBG_AUTH, "\tauth_rpc read failed: %r\n");
  130. goto Die;
  131. }
  132. decr = strtomp(rpc->arg, nil, 16, nil);
  133. if(decr == nil){
  134. debug(DBG_AUTH, "\tdecr %s failed\n", rpc->arg);
  135. goto Die;
  136. }
  137. debug(DBG_AUTH, "\tdecrypted %B\n", decr);
  138. unpad = rsaunpad(decr);
  139. if(unpad == nil){
  140. debug(DBG_AUTH, "\tunpad %B failed\n", decr);
  141. mpfree(decr);
  142. goto Die;
  143. }
  144. debug(DBG_AUTH, "\tunpadded %B\n", unpad);
  145. mpfree(decr);
  146. mptoberjust(unpad, chalbuf, 32);
  147. mpfree(unpad);
  148. auth_freerpc(rpc);
  149. close(afd);
  150. return 0;
  151. }
  152. int
  153. startagent(Conn *c)
  154. {
  155. int ret;
  156. Msg *m;
  157. m = allocmsg(c, SSH_CMSG_AGENT_REQUEST_FORWARDING, 0);
  158. sendmsg(m);
  159. m = recvmsg(c, 0);
  160. if(m == nil)
  161. error(Ehangup);
  162. switch(m->type){
  163. case SSH_SMSG_SUCCESS:
  164. debug(DBG_AUTH, "agent allocated\n");
  165. ret = 0;
  166. break;
  167. case SSH_SMSG_FAILURE:
  168. debug(DBG_AUTH, "agent failed to allocate\n");
  169. ret = -1;
  170. break;
  171. default:
  172. badmsg(m, 0);
  173. ret = -1;
  174. break;
  175. }
  176. free(m);
  177. return ret;
  178. }
  179. void handlefullmsg(Conn*, Achan*);
  180. void
  181. handleagentmsg(Msg *m)
  182. {
  183. u32int chan, len;
  184. int n;
  185. Achan *a;
  186. assert(m->type == SSH_MSG_CHANNEL_DATA);
  187. debug(DBG_AUTH, "agent data\n");
  188. debug(DBG_AUTH, "\t%.*H\n", m->ep-m->rp, m->rp);
  189. chan = getlong(m);
  190. len = getlong(m);
  191. if(m->rp+len != m->ep)
  192. sysfatal("got bad channel data");
  193. if(chan >= nelem(achan))
  194. error("bad channel in agent request");
  195. a = &achan[chan];
  196. while(m->rp < m->ep){
  197. if(a->nlbuf < 4){
  198. a->lbuf[a->nlbuf++] = getbyte(m);
  199. if(a->nlbuf == 4){
  200. a->len = (a->lbuf[0]<<24) | (a->lbuf[1]<<16) | (a->lbuf[2]<<8) | a->lbuf[3];
  201. a->data = erealloc(a->data, a->len);
  202. a->ndata = 0;
  203. }
  204. continue;
  205. }
  206. if(a->ndata < a->len){
  207. n = a->len - a->ndata;
  208. if(n > m->ep - m->rp)
  209. n = m->ep - m->rp;
  210. memmove(a->data+a->ndata, getbytes(m, n), n);
  211. a->ndata += n;
  212. }
  213. if(a->ndata == a->len){
  214. handlefullmsg(m->c, a);
  215. a->nlbuf = 0;
  216. }
  217. }
  218. }
  219. void
  220. handlefullmsg(Conn *c, Achan *a)
  221. {
  222. int i;
  223. u32int chan, len, n, rt;
  224. uchar type;
  225. Msg *m, mm;
  226. Msg *r;
  227. Key *k;
  228. int nk;
  229. mpint *mod, *ek, *chal;
  230. uchar sessid[16];
  231. uchar chalbuf[32];
  232. uchar digest[16];
  233. DigestState *s;
  234. static int first;
  235. assert(a->len == a->ndata);
  236. chan = a->chan;
  237. mm.rp = a->data;
  238. mm.ep = a->data+a->ndata;
  239. mm.c = c;
  240. m = &mm;
  241. type = getbyte(m);
  242. if(first == 0){
  243. first++;
  244. fmtinstall('H', encodefmt);
  245. }
  246. switch(type){
  247. default:
  248. debug(DBG_AUTH, "unknown msg type\n");
  249. Failure:
  250. debug(DBG_AUTH, "agent sending failure\n");
  251. r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13);
  252. putlong(r, chan);
  253. putlong(r, 5);
  254. putlong(r, 1);
  255. putbyte(r, SSH_AGENT_FAILURE);
  256. sendmsg(r);
  257. return;
  258. case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
  259. debug(DBG_AUTH, "agent request identities\n");
  260. nk = listkeys(&k);
  261. if(nk < 0)
  262. goto Failure;
  263. len = 1+4; /* type, nk */
  264. for(i=0; i<nk; i++){
  265. len += 4;
  266. len += 2+(mpsignif(k[i].ek)+7)/8;
  267. len += 2+(mpsignif(k[i].mod)+7)/8;
  268. len += 4+strlen(k[i].comment);
  269. }
  270. r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+len);
  271. putlong(r, chan);
  272. putlong(r, len+4);
  273. putlong(r, len);
  274. putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER);
  275. putlong(r, nk);
  276. for(i=0; i<nk; i++){
  277. debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment);
  278. putlong(r, mpsignif(k[i].mod));
  279. putmpint(r, k[i].ek);
  280. putmpint(r, k[i].mod);
  281. putstring(r, k[i].comment);
  282. mpfree(k[i].ek);
  283. mpfree(k[i].mod);
  284. free(k[i].comment);
  285. }
  286. free(k);
  287. sendmsg(r);
  288. break;
  289. case SSH_AGENTC_RSA_CHALLENGE:
  290. n = getlong(m);
  291. USED(n); /* number of bits in key; who cares? */
  292. ek = getmpint(m);
  293. mod = getmpint(m);
  294. chal = getmpint(m);
  295. memmove(sessid, getbytes(m, 16), 16);
  296. rt = getlong(m);
  297. debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n",
  298. ek, mod, chal, rt, m->rp, m->ep);
  299. if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){
  300. mpfree(ek);
  301. mpfree(mod);
  302. mpfree(chal);
  303. goto Failure;
  304. }
  305. s = md5(chalbuf, 32, nil, nil);
  306. md5(sessid, 16, digest, s);
  307. r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16);
  308. putlong(r, chan);
  309. putlong(r, 4+16+1);
  310. putlong(r, 16+1);
  311. putbyte(r, SSH_AGENT_RSA_RESPONSE);
  312. putbytes(r, digest, 16);
  313. debug(DBG_AUTH, "digest %.16H\n", digest);
  314. sendmsg(r);
  315. mpfree(ek);
  316. mpfree(mod);
  317. mpfree(chal);
  318. return;
  319. case SSH_AGENTC_ADD_RSA_IDENTITY:
  320. goto Failure;
  321. /*
  322. n = getlong(m);
  323. pubmod = getmpint(m);
  324. pubexp = getmpint(m);
  325. privexp = getmpint(m);
  326. pinversemodq = getmpint(m);
  327. p = getmpint(m);
  328. q = getmpint(m);
  329. comment = getstring(m);
  330. add to factotum;
  331. send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
  332. */
  333. case SSH_AGENTC_REMOVE_RSA_IDENTITY:
  334. goto Failure;
  335. /*
  336. n = getlong(m);
  337. pubmod = getmpint(m);
  338. pubexp = getmpint(m);
  339. tell factotum to del key
  340. send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
  341. */
  342. }
  343. }
  344. void
  345. handleagentopen(Msg *m)
  346. {
  347. int i;
  348. u32int remote;
  349. assert(m->type == SSH_SMSG_AGENT_OPEN);
  350. remote = getlong(m);
  351. debug(DBG_AUTH, "agent open %d\n", remote);
  352. for(i=0; i<nelem(achan); i++)
  353. if(achan[i].open == 0 && achan[i].needeof == 0 && achan[i].needclosed == 0)
  354. break;
  355. if(i == nelem(achan)){
  356. m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_FAILURE, 4);
  357. putlong(m, remote);
  358. sendmsg(m);
  359. return;
  360. }
  361. debug(DBG_AUTH, "\tremote %d is local %d\n", remote, i);
  362. achan[i].open = 1;
  363. achan[i].needeof = 1;
  364. achan[i].needclosed = 1;
  365. achan[i].nlbuf = 0;
  366. achan[i].chan = remote;
  367. m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 8);
  368. putlong(m, remote);
  369. putlong(m, i);
  370. sendmsg(m);
  371. }
  372. void
  373. handleagentieof(Msg *m)
  374. {
  375. u32int local;
  376. assert(m->type == SSH_MSG_CHANNEL_INPUT_EOF);
  377. local = getlong(m);
  378. debug(DBG_AUTH, "agent close %d\n", local);
  379. if(local < nelem(achan)){
  380. debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
  381. achan[local].open = 0;
  382. /*
  383. m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
  384. putlong(m, achan[local].chan);
  385. sendmsg(m);
  386. */
  387. if(achan[local].needeof){
  388. achan[local].needeof = 0;
  389. m = allocmsg(m->c, SSH_MSG_CHANNEL_INPUT_EOF, 4);
  390. putlong(m, achan[local].chan);
  391. sendmsg(m);
  392. }
  393. }
  394. }
  395. void
  396. handleagentoclose(Msg *m)
  397. {
  398. u32int local;
  399. assert(m->type == SSH_MSG_CHANNEL_OUTPUT_CLOSED);
  400. local = getlong(m);
  401. debug(DBG_AUTH, "agent close %d\n", local);
  402. if(local < nelem(achan)){
  403. debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
  404. if(achan[local].needclosed){
  405. achan[local].needclosed = 0;
  406. m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
  407. putlong(m, achan[local].chan);
  408. sendmsg(m);
  409. }
  410. }
  411. }