p9sk1.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /*
  2. * p9sk1, p9sk2 - Plan 9 secret (private) key authentication.
  3. * p9sk2 is an incomplete flawed variant of p9sk1.
  4. *
  5. * Client protocol:
  6. * write challenge[challen] (p9sk1 only)
  7. * read tickreq[tickreqlen]
  8. * write ticket[ticketlen]
  9. * read authenticator[authentlen]
  10. *
  11. * Server protocol:
  12. * read challenge[challen] (p9sk1 only)
  13. * write tickreq[tickreqlen]
  14. * read ticket[ticketlen]
  15. * write authenticator[authentlen]
  16. */
  17. #include "dat.h"
  18. struct State
  19. {
  20. int vers;
  21. Key *key;
  22. Ticket t;
  23. Ticketreq tr;
  24. char cchal[CHALLEN];
  25. char tbuf[TICKETLEN+AUTHENTLEN];
  26. char authkey[DESKEYLEN];
  27. uchar *secret;
  28. int speakfor;
  29. };
  30. enum
  31. {
  32. /* client phases */
  33. CHaveChal,
  34. CNeedTreq,
  35. CHaveTicket,
  36. CNeedAuth,
  37. /* server phases */
  38. SNeedChal,
  39. SHaveTreq,
  40. SNeedTicket,
  41. SHaveAuth,
  42. Maxphase,
  43. };
  44. static char *phasenames[Maxphase] =
  45. {
  46. [CHaveChal] "CHaveChal",
  47. [CNeedTreq] "CNeedTreq",
  48. [CHaveTicket] "CHaveTicket",
  49. [CNeedAuth] "CNeedAuth",
  50. [SNeedChal] "SNeedChal",
  51. [SHaveTreq] "SHaveTreq",
  52. [SNeedTicket] "SNeedTicket",
  53. [SHaveAuth] "SHaveAuth",
  54. };
  55. static int gettickets(State*, char*, char*);
  56. static int
  57. p9skinit(Proto *p, Fsstate *fss)
  58. {
  59. State *s;
  60. int iscli, ret;
  61. Key *k;
  62. Keyinfo ki;
  63. Attr *attr;
  64. if((iscli = isclient(_strfindattr(fss->attr, "role"))) < 0)
  65. return failure(fss, nil);
  66. s = emalloc(sizeof *s);
  67. fss = fss;
  68. fss->phasename = phasenames;
  69. fss->maxphase = Maxphase;
  70. if(p == &p9sk1)
  71. s->vers = 1;
  72. else if(p == &p9sk2)
  73. s->vers = 2;
  74. else
  75. abort();
  76. if(iscli){
  77. switch(s->vers){
  78. case 1:
  79. fss->phase = CHaveChal;
  80. memrandom(s->cchal, CHALLEN);
  81. break;
  82. case 2:
  83. fss->phase = CNeedTreq;
  84. break;
  85. }
  86. }else{
  87. s->tr.type = AuthTreq;
  88. attr = setattr(_copyattr(fss->attr), "proto=p9sk1");
  89. mkkeyinfo(&ki, fss, attr);
  90. ki.user = nil;
  91. ret = findkey(&k, &ki, "user? dom?");
  92. _freeattr(attr);
  93. if(ret != RpcOk){
  94. free(s);
  95. return ret;
  96. }
  97. safecpy(s->tr.authid, _strfindattr(k->attr, "user"), sizeof(s->tr.authid));
  98. safecpy(s->tr.authdom, _strfindattr(k->attr, "dom"), sizeof(s->tr.authdom));
  99. s->key = k;
  100. memrandom(s->tr.chal, sizeof s->tr.chal);
  101. switch(s->vers){
  102. case 1:
  103. fss->phase = SNeedChal;
  104. break;
  105. case 2:
  106. fss->phase = SHaveTreq;
  107. memmove(s->cchal, s->tr.chal, CHALLEN);
  108. break;
  109. }
  110. }
  111. fss->ps = s;
  112. return RpcOk;
  113. }
  114. static int
  115. p9skread(Fsstate *fss, void *a, uint *n)
  116. {
  117. int m;
  118. State *s;
  119. s = fss->ps;
  120. switch(fss->phase){
  121. default:
  122. return phaseerror(fss, "read");
  123. case CHaveChal:
  124. m = CHALLEN;
  125. if(*n < m)
  126. return toosmall(fss, m);
  127. *n = m;
  128. memmove(a, s->cchal, m);
  129. fss->phase = CNeedTreq;
  130. return RpcOk;
  131. case SHaveTreq:
  132. m = TICKREQLEN;
  133. if(*n < m)
  134. return toosmall(fss, m);
  135. *n = m;
  136. convTR2M(&s->tr, a);
  137. fss->phase = SNeedTicket;
  138. return RpcOk;
  139. case CHaveTicket:
  140. m = TICKETLEN+AUTHENTLEN;
  141. if(*n < m)
  142. return toosmall(fss, m);
  143. *n = m;
  144. memmove(a, s->tbuf, m);
  145. fss->phase = CNeedAuth;
  146. return RpcOk;
  147. case SHaveAuth:
  148. m = AUTHENTLEN;
  149. if(*n < m)
  150. return toosmall(fss, m);
  151. *n = m;
  152. memmove(a, s->tbuf+TICKETLEN, m);
  153. fss->ai.cuid = s->t.cuid;
  154. fss->ai.suid = s->t.suid;
  155. s->secret = emalloc(8);
  156. des56to64((uchar*)s->t.key, s->secret);
  157. fss->ai.secret = s->secret;
  158. fss->ai.nsecret = 8;
  159. fss->haveai = 1;
  160. fss->phase = Established;
  161. return RpcOk;
  162. }
  163. }
  164. static int
  165. p9skwrite(Fsstate *fss, void *a, uint n)
  166. {
  167. int m, ret, sret;
  168. char tbuf[2*TICKETLEN], trbuf[TICKREQLEN], *user;
  169. Attr *attr;
  170. Authenticator auth;
  171. State *s;
  172. Key *srvkey;
  173. Keyinfo ki;
  174. s = fss->ps;
  175. switch(fss->phase){
  176. default:
  177. return phaseerror(fss, "write");
  178. case SNeedChal:
  179. m = CHALLEN;
  180. if(n < m)
  181. return toosmall(fss, m);
  182. memmove(s->cchal, a, m);
  183. fss->phase = SHaveTreq;
  184. return RpcOk;
  185. case CNeedTreq:
  186. m = TICKREQLEN;
  187. if(n < m)
  188. return toosmall(fss, m);
  189. /* remember server's chal */
  190. convM2TR(a, &s->tr);
  191. if(s->vers == 2)
  192. memmove(s->cchal, s->tr.chal, CHALLEN);
  193. if(s->key != nil)
  194. closekey(s->key);
  195. attr = _delattr(_delattr(_copyattr(fss->attr), "role"), "user");
  196. attr = setattr(attr, "proto=p9sk1");
  197. user = _strfindattr(fss->attr, "user");
  198. /*
  199. * If our client is the user who started factotum (client==owner), then
  200. * he can use whatever keys we have to speak as whoever he pleases.
  201. * If, on the other hand, we're speaking on behalf of someone else,
  202. * we will only vouch for their name on the local system.
  203. *
  204. * We do the sysuser findkey second so that if we return RpcNeedkey,
  205. * the correct key information gets asked for.
  206. */
  207. srvkey = nil;
  208. s->speakfor = 0;
  209. sret = RpcFailure;
  210. if(user==nil || strcmp(user, fss->sysuser) == 0){
  211. mkkeyinfo(&ki, fss, attr);
  212. ki.user = nil;
  213. sret = findkey(&srvkey, &ki,
  214. "role=speakfor dom=%q user?", s->tr.authdom);
  215. }
  216. if(user != nil)
  217. attr = setattr(attr, "user=%q", user);
  218. mkkeyinfo(&ki, fss, attr);
  219. ret = findkey(&s->key, &ki,
  220. "role=client dom=%q %s", s->tr.authdom, p9sk1.keyprompt);
  221. if(ret == RpcOk)
  222. closekey(srvkey);
  223. else if(sret == RpcOk){
  224. s->key = srvkey;
  225. s->speakfor = 1;
  226. }else if(ret == RpcConfirm || sret == RpcConfirm){
  227. _freeattr(attr);
  228. return RpcConfirm;
  229. }else{
  230. _freeattr(attr);
  231. return ret;
  232. }
  233. /* fill in the rest of the request */
  234. s->tr.type = AuthTreq;
  235. safecpy(s->tr.hostid, _strfindattr(s->key->attr, "user"), sizeof s->tr.hostid);
  236. if(s->speakfor)
  237. safecpy(s->tr.uid, fss->sysuser, sizeof s->tr.uid);
  238. else
  239. safecpy(s->tr.uid, s->tr.hostid, sizeof s->tr.uid);
  240. convTR2M(&s->tr, trbuf);
  241. /* get tickets, from auth server or invent if we can */
  242. if(gettickets(s, trbuf, tbuf) < 0){
  243. _freeattr(attr);
  244. return failure(fss, nil);
  245. }
  246. convM2T(tbuf, &s->t, (char*)s->key->priv);
  247. if(s->t.num != AuthTc){
  248. if(s->key->successes == 0 && !s->speakfor)
  249. disablekey(s->key);
  250. if(askforkeys && !s->speakfor){
  251. snprint(fss->keyinfo, sizeof fss->keyinfo,
  252. "%A %s", attr, p9sk1.keyprompt);
  253. _freeattr(attr);
  254. return RpcNeedkey;
  255. }else{
  256. _freeattr(attr);
  257. return failure(fss, Ebadkey);
  258. }
  259. }
  260. s->key->successes++;
  261. _freeattr(attr);
  262. memmove(s->tbuf, tbuf+TICKETLEN, TICKETLEN);
  263. auth.num = AuthAc;
  264. memmove(auth.chal, s->tr.chal, CHALLEN);
  265. auth.id = 0;
  266. convA2M(&auth, s->tbuf+TICKETLEN, s->t.key);
  267. fss->phase = CHaveTicket;
  268. return RpcOk;
  269. case SNeedTicket:
  270. m = TICKETLEN+AUTHENTLEN;
  271. if(n < m)
  272. return toosmall(fss, m);
  273. convM2T(a, &s->t, (char*)s->key->priv);
  274. if(s->t.num != AuthTs
  275. || memcmp(s->t.chal, s->tr.chal, CHALLEN) != 0)
  276. return failure(fss, Easproto);
  277. convM2A((char*)a+TICKETLEN, &auth, s->t.key);
  278. if(auth.num != AuthAc
  279. || memcmp(auth.chal, s->tr.chal, CHALLEN) != 0
  280. || auth.id != 0)
  281. return failure(fss, Easproto);
  282. auth.num = AuthAs;
  283. memmove(auth.chal, s->cchal, CHALLEN);
  284. auth.id = 0;
  285. convA2M(&auth, s->tbuf+TICKETLEN, s->t.key);
  286. fss->phase = SHaveAuth;
  287. return RpcOk;
  288. case CNeedAuth:
  289. m = AUTHENTLEN;
  290. if(n < m)
  291. return toosmall(fss, m);
  292. convM2A(a, &auth, s->t.key);
  293. if(auth.num != AuthAs
  294. || memcmp(auth.chal, s->cchal, CHALLEN) != 0
  295. || auth.id != 0)
  296. return failure(fss, Easproto);
  297. fss->ai.cuid = s->t.cuid;
  298. fss->ai.suid = s->t.suid;
  299. s->secret = emalloc(8);
  300. des56to64((uchar*)s->t.key, s->secret);
  301. fss->ai.secret = s->secret;
  302. fss->ai.nsecret = 8;
  303. fss->haveai = 1;
  304. fss->phase = Established;
  305. return RpcOk;
  306. }
  307. }
  308. static void
  309. p9skclose(Fsstate *fss)
  310. {
  311. State *s;
  312. s = fss->ps;
  313. if(s->secret != nil){
  314. free(s->secret);
  315. s->secret = nil;
  316. }
  317. if(s->key != nil){
  318. closekey(s->key);
  319. s->key = nil;
  320. }
  321. free(s);
  322. }
  323. static int
  324. unhex(char c)
  325. {
  326. if('0' <= c && c <= '9')
  327. return c-'0';
  328. if('a' <= c && c <= 'f')
  329. return c-'a'+10;
  330. if('A' <= c && c <= 'F')
  331. return c-'A'+10;
  332. abort();
  333. return -1;
  334. }
  335. static int
  336. hexparse(char *hex, uchar *dat, int ndat)
  337. {
  338. int i;
  339. if(strlen(hex) != 2*ndat)
  340. return -1;
  341. if(hex[strspn(hex, "0123456789abcdefABCDEF")] != '\0')
  342. return -1;
  343. for(i=0; i<ndat; i++)
  344. dat[i] = (unhex(hex[2*i])<<4)|unhex(hex[2*i+1]);
  345. return 0;
  346. }
  347. static int
  348. p9skaddkey(Key *k, int before)
  349. {
  350. char *s;
  351. k->priv = emalloc(DESKEYLEN);
  352. if(s = _strfindattr(k->privattr, "!hex")){
  353. if(hexparse(s, k->priv, 7) < 0){
  354. free(k->priv);
  355. k->priv = nil;
  356. werrstr("malformed key data");
  357. return -1;
  358. }
  359. }else if(s = _strfindattr(k->privattr, "!password")){
  360. passtokey((char*)k->priv, s);
  361. }else{
  362. werrstr("no key data");
  363. free(k->priv);
  364. k->priv = nil;
  365. return -1;
  366. }
  367. return replacekey(k, before);
  368. }
  369. static void
  370. p9skclosekey(Key *k)
  371. {
  372. free(k->priv);
  373. }
  374. static int
  375. getastickets(State *s, char *trbuf, char *tbuf)
  376. {
  377. int asfd, rv;
  378. char *dom;
  379. if((dom = _strfindattr(s->key->attr, "dom")) == nil){
  380. werrstr("auth key has no domain");
  381. return -1;
  382. }
  383. asfd = _authdial(nil, dom);
  384. if(asfd < 0)
  385. return -1;
  386. rv = _asgetticket(asfd, trbuf, tbuf);
  387. close(asfd);
  388. return rv;
  389. }
  390. static int
  391. mkserverticket(State *s, char *tbuf)
  392. {
  393. Ticketreq *tr = &s->tr;
  394. Ticket t;
  395. if(strcmp(tr->authid, tr->hostid) != 0)
  396. return -1;
  397. /* this keeps creating accounts on martha from working. -- presotto
  398. if(strcmp(tr->uid, "none") == 0)
  399. return -1;
  400. */
  401. memset(&t, 0, sizeof(t));
  402. memmove(t.chal, tr->chal, CHALLEN);
  403. strcpy(t.cuid, tr->uid);
  404. strcpy(t.suid, tr->uid);
  405. memrandom(t.key, DESKEYLEN);
  406. t.num = AuthTc;
  407. convT2M(&t, tbuf, s->key->priv);
  408. t.num = AuthTs;
  409. convT2M(&t, tbuf+TICKETLEN, s->key->priv);
  410. return 0;
  411. }
  412. static int
  413. gettickets(State *s, char *trbuf, char *tbuf)
  414. {
  415. /*
  416. if(mktickets(s, trbuf, tbuf) >= 0)
  417. return 0;
  418. */
  419. if(getastickets(s, trbuf, tbuf) >= 0)
  420. return 0;
  421. return mkserverticket(s, tbuf);
  422. }
  423. Proto p9sk1 = {
  424. .name= "p9sk1",
  425. .init= p9skinit,
  426. .write= p9skwrite,
  427. .read= p9skread,
  428. .close= p9skclose,
  429. .addkey= p9skaddkey,
  430. .closekey= p9skclosekey,
  431. .keyprompt= "user? !password?"
  432. };
  433. Proto p9sk2 = {
  434. .name= "p9sk2",
  435. .init= p9skinit,
  436. .write= p9skwrite,
  437. .read= p9skread,
  438. .close= p9skclose,
  439. };