agent.c 9.3 KB

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