p9sk1.c 9.4 KB

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