agent.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  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, "rsa") != 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=rsa service=ssh 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. switch(m->type){
  161. case SSH_SMSG_SUCCESS:
  162. debug(DBG_AUTH, "agent allocated\n");
  163. ret = 0;
  164. break;
  165. case SSH_SMSG_FAILURE:
  166. debug(DBG_AUTH, "agent failed to allocate\n");
  167. ret = -1;
  168. break;
  169. default:
  170. badmsg(m, 0);
  171. ret = -1;
  172. break;
  173. }
  174. free(m);
  175. return ret;
  176. }
  177. void handlefullmsg(Conn*, Achan*);
  178. void
  179. handleagentmsg(Msg *m)
  180. {
  181. u32int chan, len;
  182. int n;
  183. Achan *a;
  184. assert(m->type == SSH_MSG_CHANNEL_DATA);
  185. debug(DBG_AUTH, "agent data\n");
  186. debug(DBG_AUTH, "\t%.*H\n", m->ep-m->rp, m->rp);
  187. chan = getlong(m);
  188. len = getlong(m);
  189. if(m->rp+len != m->ep)
  190. sysfatal("got bad channel data");
  191. if(chan >= nelem(achan))
  192. error("bad channel in agent request");
  193. a = &achan[chan];
  194. while(m->rp < m->ep){
  195. if(a->nlbuf < 4){
  196. a->lbuf[a->nlbuf++] = getbyte(m);
  197. if(a->nlbuf == 4){
  198. a->len = (a->lbuf[0]<<24) | (a->lbuf[1]<<16) | (a->lbuf[2]<<8) | a->lbuf[3];
  199. a->data = erealloc(a->data, a->len);
  200. a->ndata = 0;
  201. }
  202. continue;
  203. }
  204. if(a->ndata < a->len){
  205. n = a->len - a->ndata;
  206. if(n > m->ep - m->rp)
  207. n = m->ep - m->rp;
  208. memmove(a->data+a->ndata, getbytes(m, n), n);
  209. a->ndata += n;
  210. }
  211. if(a->ndata == a->len){
  212. handlefullmsg(m->c, a);
  213. a->nlbuf = 0;
  214. }
  215. }
  216. }
  217. void
  218. handlefullmsg(Conn *c, Achan *a)
  219. {
  220. int i;
  221. u32int chan, len, n, rt;
  222. uchar type;
  223. Msg *m, mm;
  224. Msg *r;
  225. Key *k;
  226. int nk;
  227. mpint *mod, *ek, *chal;
  228. uchar sessid[16];
  229. uchar chalbuf[32];
  230. uchar digest[16];
  231. DigestState *s;
  232. static int first;
  233. assert(a->len == a->ndata);
  234. chan = a->chan;
  235. mm.rp = a->data;
  236. mm.ep = a->data+a->ndata;
  237. mm.c = c;
  238. m = &mm;
  239. type = getbyte(m);
  240. if(first == 0){
  241. first++;
  242. fmtinstall('H', encodefmt);
  243. }
  244. switch(type){
  245. default:
  246. debug(DBG_AUTH, "unknown msg type\n");
  247. Failure:
  248. debug(DBG_AUTH, "agent sending failure\n");
  249. r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13);
  250. putlong(r, chan);
  251. putlong(r, 5);
  252. putlong(r, 1);
  253. putbyte(r, SSH_AGENT_FAILURE);
  254. sendmsg(r);
  255. return;
  256. case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
  257. debug(DBG_AUTH, "agent request identities\n");
  258. nk = listkeys(&k);
  259. if(nk < 0)
  260. goto Failure;
  261. len = 1+4; /* type, nk */
  262. for(i=0; i<nk; i++){
  263. len += 4;
  264. len += 2+(mpsignif(k[i].ek)+7)/8;
  265. len += 2+(mpsignif(k[i].mod)+7)/8;
  266. len += 4+strlen(k[i].comment);
  267. }
  268. r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+len);
  269. putlong(r, chan);
  270. putlong(r, len+4);
  271. putlong(r, len);
  272. putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER);
  273. putlong(r, nk);
  274. for(i=0; i<nk; i++){
  275. debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment);
  276. putlong(r, mpsignif(k[i].mod));
  277. putmpint(r, k[i].ek);
  278. putmpint(r, k[i].mod);
  279. putstring(r, k[i].comment);
  280. mpfree(k[i].ek);
  281. mpfree(k[i].mod);
  282. free(k[i].comment);
  283. }
  284. free(k);
  285. sendmsg(r);
  286. break;
  287. case SSH_AGENTC_RSA_CHALLENGE:
  288. n = getlong(m);
  289. USED(n); /* number of bits in key; who cares? */
  290. ek = getmpint(m);
  291. mod = getmpint(m);
  292. chal = getmpint(m);
  293. memmove(sessid, getbytes(m, 16), 16);
  294. rt = getlong(m);
  295. debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n",
  296. ek, mod, chal, rt, m->rp, m->ep);
  297. if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){
  298. mpfree(ek);
  299. mpfree(mod);
  300. mpfree(chal);
  301. goto Failure;
  302. }
  303. s = md5(chalbuf, 32, nil, nil);
  304. md5(sessid, 16, digest, s);
  305. r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16);
  306. putlong(r, chan);
  307. putlong(r, 4+16+1);
  308. putlong(r, 16+1);
  309. putbyte(r, SSH_AGENT_RSA_RESPONSE);
  310. putbytes(r, digest, 16);
  311. debug(DBG_AUTH, "digest %.16H\n", digest);
  312. sendmsg(r);
  313. mpfree(ek);
  314. mpfree(mod);
  315. mpfree(chal);
  316. return;
  317. case SSH_AGENTC_ADD_RSA_IDENTITY:
  318. goto Failure;
  319. /*
  320. n = getlong(m);
  321. pubmod = getmpint(m);
  322. pubexp = getmpint(m);
  323. privexp = getmpint(m);
  324. pinversemodq = getmpint(m);
  325. p = getmpint(m);
  326. q = getmpint(m);
  327. comment = getstring(m);
  328. add to factotum;
  329. send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
  330. */
  331. case SSH_AGENTC_REMOVE_RSA_IDENTITY:
  332. goto Failure;
  333. /*
  334. n = getlong(m);
  335. pubmod = getmpint(m);
  336. pubexp = getmpint(m);
  337. tell factotum to del key
  338. send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE;
  339. */
  340. }
  341. }
  342. void
  343. handleagentopen(Msg *m)
  344. {
  345. int i;
  346. u32int remote;
  347. assert(m->type == SSH_SMSG_AGENT_OPEN);
  348. remote = getlong(m);
  349. debug(DBG_AUTH, "agent open %d\n", remote);
  350. for(i=0; i<nelem(achan); i++)
  351. if(achan[i].open == 0 && achan[i].needeof == 0 && achan[i].needclosed == 0)
  352. break;
  353. if(i == nelem(achan)){
  354. m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_FAILURE, 4);
  355. putlong(m, remote);
  356. sendmsg(m);
  357. return;
  358. }
  359. debug(DBG_AUTH, "\tremote %d is local %d\n", remote, i);
  360. achan[i].open = 1;
  361. achan[i].needeof = 1;
  362. achan[i].needclosed = 1;
  363. achan[i].nlbuf = 0;
  364. achan[i].chan = remote;
  365. m = allocmsg(m->c, SSH_MSG_CHANNEL_OPEN_CONFIRMATION, 8);
  366. putlong(m, remote);
  367. putlong(m, i);
  368. sendmsg(m);
  369. }
  370. void
  371. handleagentieof(Msg *m)
  372. {
  373. u32int local;
  374. assert(m->type == SSH_MSG_CHANNEL_INPUT_EOF);
  375. local = getlong(m);
  376. debug(DBG_AUTH, "agent close %d\n", local);
  377. if(local < nelem(achan)){
  378. debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
  379. achan[local].open = 0;
  380. /*
  381. m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
  382. putlong(m, achan[local].chan);
  383. sendmsg(m);
  384. */
  385. if(achan[local].needeof){
  386. achan[local].needeof = 0;
  387. m = allocmsg(m->c, SSH_MSG_CHANNEL_INPUT_EOF, 4);
  388. putlong(m, achan[local].chan);
  389. sendmsg(m);
  390. }
  391. }
  392. }
  393. void
  394. handleagentoclose(Msg *m)
  395. {
  396. u32int local;
  397. assert(m->type == SSH_MSG_CHANNEL_OUTPUT_CLOSED);
  398. local = getlong(m);
  399. debug(DBG_AUTH, "agent close %d\n", local);
  400. if(local < nelem(achan)){
  401. debug(DBG_AUTH, "\tlocal %d is remote %d\n", local, achan[local].chan);
  402. if(achan[local].needclosed){
  403. achan[local].needclosed = 0;
  404. m = allocmsg(m->c, SSH_MSG_CHANNEL_OUTPUT_CLOSED, 4);
  405. putlong(m, achan[local].chan);
  406. sendmsg(m);
  407. }
  408. }
  409. }