secstore.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  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. /*
  10. * Various files from /sys/src/cmd/auth/secstore, just enough
  11. * to download a file at boot time.
  12. */
  13. #include "dat.h"
  14. #include <ip.h>
  15. enum{ CHK = 16};
  16. enum{ MAXFILESIZE = 10*1024*1024 };
  17. enum{// PW status bits
  18. Enabled = (1<<0),
  19. STA = (1<<1), // extra SecurID step
  20. };
  21. static char testmess[] = "__secstore\tPAK\nC=%s\nm=0\n";
  22. int
  23. havesecstore(void)
  24. {
  25. int m, n, fd;
  26. uint8_t buf[500];
  27. n = snprint((char*)buf, sizeof buf, testmess, owner);
  28. hnputs(buf, 0x8000+n-2);
  29. fd = secdial();
  30. if(fd < 0)
  31. return 0;
  32. if(write(fd, buf, n) != n || readn(fd, buf, 2) != 2){
  33. close(fd);
  34. return 0;
  35. }
  36. n = ((buf[0]&0x7f)<<8) + buf[1];
  37. if(n+1 > sizeof buf){
  38. werrstr("implausibly large count %d", n);
  39. close(fd);
  40. return 0;
  41. }
  42. m = readn(fd, buf, n);
  43. close(fd);
  44. if(m != n){
  45. if(m >= 0)
  46. werrstr("short read from secstore");
  47. return 0;
  48. }
  49. buf[n] = 0;
  50. if(strcmp((char*)buf, "!account expired") == 0){
  51. werrstr("account expired");
  52. return 0;
  53. }
  54. return strcmp((char*)buf, "!account exists") == 0;
  55. }
  56. // delimited, authenticated, encrypted connection
  57. enum{ Maxmsg=4096 }; // messages > Maxmsg bytes are truncated
  58. typedef struct SConn SConn;
  59. extern SConn* newSConn(int); // arg is open file descriptor
  60. struct SConn{
  61. void *chan;
  62. int secretlen;
  63. int (*secret)(SConn*, uint8_t*, int);//
  64. int (*read)(SConn*, uint8_t*, int); // <0 if error; errmess in buffer
  65. int (*write)(SConn*, uint8_t*, int);
  66. void (*free)(SConn*); // also closes file descriptor
  67. };
  68. // secret(s,b,dir) sets secret for digest, encrypt, using the secretlen
  69. // bytes in b to form keys for the two directions;
  70. // set dir=0 in client, dir=1 in server
  71. // error convention: write !message in-band
  72. #define readstr secstore_readstr
  73. static void writerr(SConn*, char*);
  74. static int readstr(SConn*, char*); // call with buf of size Maxmsg+1
  75. // returns -1 upon error, with error message in buf
  76. typedef struct ConnState {
  77. uint8_t secret[SHA1dlen];
  78. uint32_t seqno;
  79. RC4state rc4;
  80. } ConnState;
  81. typedef struct SS{
  82. int fd; // file descriptor for read/write of encrypted data
  83. int alg; // if nonzero, "alg sha rc4_128"
  84. ConnState in, out;
  85. } SS;
  86. static int
  87. SC_secret(SConn *conn, uint8_t *sigma, int direction)
  88. {
  89. SS *ss = (SS*)(conn->chan);
  90. int nsigma = conn->secretlen;
  91. if(direction != 0){
  92. hmac_sha1(sigma, nsigma, (uint8_t*)"one", 3, ss->out.secret,
  93. nil);
  94. hmac_sha1(sigma, nsigma, (uint8_t*)"two", 3, ss->in.secret,
  95. nil);
  96. }else{
  97. hmac_sha1(sigma, nsigma, (uint8_t*)"two", 3, ss->out.secret,
  98. nil);
  99. hmac_sha1(sigma, nsigma, (uint8_t*)"one", 3, ss->in.secret,
  100. nil);
  101. }
  102. setupRC4state(&ss->in.rc4, ss->in.secret, 16); // restrict to 128 bits
  103. setupRC4state(&ss->out.rc4, ss->out.secret, 16);
  104. ss->alg = 1;
  105. return 0;
  106. }
  107. static void
  108. hash(uint8_t secret[SHA1dlen], uint8_t *data, int len, int seqno,
  109. uint8_t d[SHA1dlen])
  110. {
  111. DigestState sha;
  112. uint8_t seq[4];
  113. seq[0] = seqno>>24;
  114. seq[1] = seqno>>16;
  115. seq[2] = seqno>>8;
  116. seq[3] = seqno;
  117. memset(&sha, 0, sizeof sha);
  118. sha1(secret, SHA1dlen, nil, &sha);
  119. sha1(data, len, nil, &sha);
  120. sha1(seq, 4, d, &sha);
  121. }
  122. static int
  123. verify(uint8_t secret[SHA1dlen], uint8_t *data, int len, int seqno,
  124. uint8_t d[SHA1dlen])
  125. {
  126. DigestState sha;
  127. uint8_t seq[4];
  128. uint8_t digest[SHA1dlen];
  129. seq[0] = seqno>>24;
  130. seq[1] = seqno>>16;
  131. seq[2] = seqno>>8;
  132. seq[3] = seqno;
  133. memset(&sha, 0, sizeof sha);
  134. sha1(secret, SHA1dlen, nil, &sha);
  135. sha1(data, len, nil, &sha);
  136. sha1(seq, 4, digest, &sha);
  137. return memcmp(d, digest, SHA1dlen);
  138. }
  139. static int
  140. SC_read(SConn *conn, uint8_t *buf, int n)
  141. {
  142. SS *ss = (SS*)(conn->chan);
  143. uint8_t count[2], digest[SHA1dlen];
  144. int len, nr;
  145. if(read(ss->fd, count, 2) != 2 || (count[0]&0x80) == 0){
  146. werrstr("!SC_read invalid count");
  147. return -1;
  148. }
  149. len = (count[0]&0x7f)<<8 | count[1]; // SSL-style count; no pad
  150. if(ss->alg){
  151. len -= SHA1dlen;
  152. if(len <= 0 || readn(ss->fd, digest, SHA1dlen) != SHA1dlen){
  153. werrstr("!SC_read missing sha1");
  154. return -1;
  155. }
  156. if(len > n || readn(ss->fd, buf, len) != len){
  157. werrstr("!SC_read missing data");
  158. return -1;
  159. }
  160. rc4(&ss->in.rc4, digest, SHA1dlen);
  161. rc4(&ss->in.rc4, buf, len);
  162. if(verify(ss->in.secret, buf, len, ss->in.seqno, digest) != 0){
  163. werrstr("!SC_read integrity check failed");
  164. return -1;
  165. }
  166. }else{
  167. if(len <= 0 || len > n){
  168. werrstr("!SC_read implausible record length");
  169. return -1;
  170. }
  171. if( (nr = readn(ss->fd, buf, len)) != len){
  172. werrstr("!SC_read expected %d bytes, but got %d", len, nr);
  173. return -1;
  174. }
  175. }
  176. ss->in.seqno++;
  177. return len;
  178. }
  179. static int
  180. SC_write(SConn *conn, uint8_t *buf, int n)
  181. {
  182. SS *ss = (SS*)(conn->chan);
  183. uint8_t count[2], digest[SHA1dlen], enc[Maxmsg+1];
  184. int len;
  185. if(n <= 0 || n > Maxmsg+1){
  186. werrstr("!SC_write invalid n %d", n);
  187. return -1;
  188. }
  189. len = n;
  190. if(ss->alg)
  191. len += SHA1dlen;
  192. count[0] = 0x80 | len>>8;
  193. count[1] = len;
  194. if(write(ss->fd, count, 2) != 2){
  195. werrstr("!SC_write invalid count");
  196. return -1;
  197. }
  198. if(ss->alg){
  199. hash(ss->out.secret, buf, n, ss->out.seqno, digest);
  200. rc4(&ss->out.rc4, digest, SHA1dlen);
  201. memcpy(enc, buf, n);
  202. rc4(&ss->out.rc4, enc, n);
  203. if(write(ss->fd, digest, SHA1dlen) != SHA1dlen ||
  204. write(ss->fd, enc, n) != n){
  205. werrstr("!SC_write error on send");
  206. return -1;
  207. }
  208. }else{
  209. if(write(ss->fd, buf, n) != n){
  210. werrstr("!SC_write error on send");
  211. return -1;
  212. }
  213. }
  214. ss->out.seqno++;
  215. return n;
  216. }
  217. static void
  218. SC_free(SConn *conn)
  219. {
  220. SS *ss = (SS*)(conn->chan);
  221. close(ss->fd);
  222. free(ss);
  223. free(conn);
  224. }
  225. SConn*
  226. newSConn(int fd)
  227. {
  228. SS *ss;
  229. SConn *conn;
  230. if(fd < 0)
  231. return nil;
  232. ss = (SS*)emalloc(sizeof(*ss));
  233. conn = (SConn*)emalloc(sizeof(*conn));
  234. ss->fd = fd;
  235. ss->alg = 0;
  236. conn->chan = (void*)ss;
  237. conn->secretlen = SHA1dlen;
  238. conn->free = SC_free;
  239. conn->secret = SC_secret;
  240. conn->read = SC_read;
  241. conn->write = SC_write;
  242. return conn;
  243. }
  244. static void
  245. writerr(SConn *conn, char *s)
  246. {
  247. char buf[Maxmsg];
  248. snprint(buf, Maxmsg, "!%s", s);
  249. conn->write(conn, (uint8_t*)buf, strlen(buf));
  250. }
  251. static int
  252. readstr(SConn *conn, char *s)
  253. {
  254. int n;
  255. n = conn->read(conn, (uint8_t*)s, Maxmsg);
  256. if(n >= 0){
  257. s[n] = 0;
  258. if(s[0] == '!'){
  259. memmove(s, s+1, n);
  260. n = -1;
  261. }
  262. }else{
  263. strcpy(s, "read error");
  264. }
  265. return n;
  266. }
  267. static int
  268. getfile(SConn *conn, uint8_t *key, int nkey)
  269. {
  270. char *buf;
  271. int nbuf, n, nr, len;
  272. char s[Maxmsg+1], *gf, *p, *q;
  273. uint8_t skey[SHA1dlen], ib[Maxmsg+CHK], *ibr, *ibw;
  274. AESstate aes;
  275. DigestState *sha;
  276. gf = "factotum";
  277. memset(&aes, 0, sizeof aes);
  278. snprint(s, Maxmsg, "GET %s\n", gf);
  279. conn->write(conn, (uint8_t*)s, strlen(s));
  280. /* get file size */
  281. s[0] = '\0';
  282. if(readstr(conn, s) < 0){
  283. werrstr("secstore: %r");
  284. return -1;
  285. }
  286. if((len = atoi(s)) < 0){
  287. werrstr("secstore: remote file %s does not exist", gf);
  288. return -1;
  289. }else if(len > MAXFILESIZE){//assert
  290. werrstr("secstore: implausible file size %d for %s", len, gf);
  291. return -1;
  292. }
  293. ibr = ibw = ib;
  294. buf = nil;
  295. nbuf = 0;
  296. for(nr=0; nr < len;){
  297. if((n = conn->read(conn, ibw, Maxmsg)) <= 0){
  298. werrstr("secstore: empty file chunk n=%d nr=%d len=%d: %r", n, nr, len);
  299. return -1;
  300. }
  301. nr += n;
  302. ibw += n;
  303. if(!aes.setup){ /* first time, read 16 byte IV */
  304. if(n < 16){
  305. werrstr("secstore: no IV in file");
  306. return -1;
  307. }
  308. sha = sha1((uint8_t*)"aescbc file", 11, nil, nil);
  309. sha1(key, nkey, skey, sha);
  310. setupAESstate(&aes, skey, AESbsize, ibr);
  311. memset(skey, 0, sizeof skey);
  312. ibr += AESbsize;
  313. n -= AESbsize;
  314. }
  315. aesCBCdecrypt(ibw-n, n, &aes);
  316. n = ibw-ibr-CHK;
  317. if(n > 0){
  318. buf = erealloc(buf, nbuf+n+1);
  319. memmove(buf+nbuf, ibr, n);
  320. nbuf += n;
  321. ibr += n;
  322. }
  323. memmove(ib, ibr, ibw-ibr);
  324. ibw = ib + (ibw-ibr);
  325. ibr = ib;
  326. }
  327. n = ibw-ibr;
  328. if((n != CHK) || (memcmp(ib, "XXXXXXXXXXXXXXXX", CHK) != 0)){
  329. werrstr("secstore: decrypted file failed to authenticate!");
  330. free(buf);
  331. return -1;
  332. }
  333. if(nbuf == 0){
  334. werrstr("secstore got empty file");
  335. return -1;
  336. }
  337. buf[nbuf] = '\0';
  338. p = buf;
  339. n = 0;
  340. while(p){
  341. if((q = strchr(p, '\n')) != nil)
  342. *q++ = '\0';
  343. n++;
  344. if(ctlwrite(p, 0) < 0)
  345. fprint(2, "factotum: secstore(%s) line %d: %r\n", gf, n);
  346. p = q;
  347. }
  348. free(buf);
  349. return 0;
  350. }
  351. static char VERSION[] = "secstore";
  352. typedef struct PAKparams{
  353. mpint *q, *p, *r, *g;
  354. } PAKparams;
  355. static PAKparams *pak;
  356. // This group was generated by the seed EB7B6E35F7CD37B511D96C67D6688CC4DD440E1E.
  357. static void
  358. initPAKparams(void)
  359. {
  360. if(pak)
  361. return;
  362. pak = (PAKparams*)emalloc(sizeof(*pak));
  363. pak->q = strtomp("E0F0EF284E10796C5A2A511E94748BA03C795C13", nil, 16, nil);
  364. pak->p = strtomp("C41CFBE4D4846F67A3DF7DE9921A49D3B42DC33728427AB159CEC8CBBD"
  365. "B12B5F0C244F1A734AEB9840804EA3C25036AD1B61AFF3ABBC247CD4B384224567A86"
  366. "3A6F020E7EE9795554BCD08ABAD7321AF27E1E92E3DB1C6E7E94FAAE590AE9C48F96D9"
  367. "3D178E809401ABE8A534A1EC44359733475A36A70C7B425125062B1142D", nil, 16, nil);
  368. pak->r = strtomp("DF310F4E54A5FEC5D86D3E14863921E834113E060F90052AD332B3241CEF"
  369. "2497EFA0303D6344F7C819691A0F9C4A773815AF8EAECFB7EC1D98F039F17A32A7E887"
  370. "D97251A927D093F44A55577F4D70444AEBD06B9B45695EC23962B175F266895C67D21"
  371. "C4656848614D888A4", nil, 16, nil);
  372. pak->g = strtomp("2F1C308DC46B9A44B52DF7DACCE1208CCEF72F69C743ADD4D2327173444"
  373. "ED6E65E074694246E07F9FD4AE26E0FDDD9F54F813C40CB9BCD4338EA6F242AB94CD41"
  374. "0E676C290368A16B1A3594877437E516C53A6EEE5493A038A017E955E218E7819734E3E"
  375. "2A6E0BAE08B14258F8C03CC1B30E0DDADFCF7CEDF0727684D3D255F1", nil, 16, nil);
  376. }
  377. // H = (sha(ver,C,sha(passphrase)))^r mod p,
  378. // a hash function expensive to attack by brute force.
  379. static void
  380. longhash(char *ver, char *C, uint8_t *passwd, mpint *H)
  381. {
  382. uint8_t *Cp;
  383. int i, n, nver, nC;
  384. uint8_t buf[140], key[1];
  385. nver = strlen(ver);
  386. nC = strlen(C);
  387. n = nver + nC + SHA1dlen;
  388. Cp = (uint8_t*)emalloc(n);
  389. memmove(Cp, ver, nver);
  390. memmove(Cp+nver, C, nC);
  391. memmove(Cp+nver+nC, passwd, SHA1dlen);
  392. for(i = 0; i < 7; i++){
  393. key[0] = 'A'+i;
  394. hmac_sha1(Cp, n, key, sizeof key, buf+i*SHA1dlen, nil);
  395. }
  396. memset(Cp, 0, n);
  397. free(Cp);
  398. betomp(buf, sizeof buf, H);
  399. mpmod(H, pak->p, H);
  400. mpexp(H, pak->r, pak->p, H);
  401. }
  402. // Hi = H^-1 mod p
  403. static char *
  404. PAK_Hi(char *C, char *passphrase, mpint *H, mpint *Hi)
  405. {
  406. uint8_t passhash[SHA1dlen];
  407. sha1((uint8_t *)passphrase, strlen(passphrase), passhash, nil);
  408. initPAKparams();
  409. longhash(VERSION, C, passhash, H);
  410. mpinvert(H, pak->p, Hi);
  411. return mptoa(Hi, 64, nil, 0);
  412. }
  413. // another, faster, hash function for each party to
  414. // confirm that the other has the right secrets.
  415. static void
  416. shorthash(char *mess, char *C, char *S, char *m, char *mu,
  417. char *sigma, char *Hi,
  418. uint8_t *digest)
  419. {
  420. SHA1state *state;
  421. state = sha1((uint8_t*)mess, strlen(mess), 0, 0);
  422. state = sha1((uint8_t*)C, strlen(C), 0, state);
  423. state = sha1((uint8_t*)S, strlen(S), 0, state);
  424. state = sha1((uint8_t*)m, strlen(m), 0, state);
  425. state = sha1((uint8_t*)mu, strlen(mu), 0, state);
  426. state = sha1((uint8_t*)sigma, strlen(sigma), 0, state);
  427. state = sha1((uint8_t*)Hi, strlen(Hi), 0, state);
  428. state = sha1((uint8_t*)mess, strlen(mess), 0, state);
  429. state = sha1((uint8_t*)C, strlen(C), 0, state);
  430. state = sha1((uint8_t*)S, strlen(S), 0, state);
  431. state = sha1((uint8_t*)m, strlen(m), 0, state);
  432. state = sha1((uint8_t*)mu, strlen(mu), 0, state);
  433. state = sha1((uint8_t*)sigma, strlen(sigma), 0, state);
  434. sha1((uint8_t*)Hi, strlen(Hi), digest, state);
  435. }
  436. // On input, conn provides an open channel to the server;
  437. // C is the name this client calls itself;
  438. // pass is the user's passphrase
  439. // On output, session secret has been set in conn
  440. // (unless return code is negative, which means failure).
  441. // If pS is not nil, it is set to the (alloc'd) name the server calls itself.
  442. static int
  443. PAKclient(SConn *conn, char *C, char *pass, char **pS)
  444. {
  445. char *mess, *mess2, *eol, *S, *hexmu, *ks, *hexm, *hexsigma = nil, *hexHi;
  446. char kc[2*SHA1dlen+1];
  447. uint8_t digest[SHA1dlen];
  448. int rc = -1, n;
  449. mpint *x, *m = mpnew(0), *mu = mpnew(0), *sigma = mpnew(0);
  450. mpint *H = mpnew(0), *Hi = mpnew(0);
  451. hexHi = PAK_Hi(C, pass, H, Hi);
  452. // random 1<=x<=q-1; send C, m=g**x H
  453. x = mprand(164, genrandom, nil);
  454. mpmod(x, pak->q, x);
  455. if(mpcmp(x, mpzero) == 0)
  456. mpassign(mpone, x);
  457. mpexp(pak->g, x, pak->p, m);
  458. mpmul(m, H, m);
  459. mpmod(m, pak->p, m);
  460. hexm = mptoa(m, 64, nil, 0);
  461. mess = (char*)emalloc(2*Maxmsg+2);
  462. mess2 = mess+Maxmsg+1;
  463. snprint(mess, Maxmsg, "%s\tPAK\nC=%s\nm=%s\n", VERSION, C, hexm);
  464. conn->write(conn, (uint8_t*)mess, strlen(mess));
  465. // recv g**y, S, check hash1(g**xy)
  466. if(readstr(conn, mess) < 0){
  467. fprint(2, "factotum: error: %s\n", mess);
  468. writerr(conn, "couldn't read g**y");
  469. goto done;
  470. }
  471. eol = strchr(mess, '\n');
  472. if(strncmp("mu=", mess, 3) != 0 || !eol || strncmp("\nk=", eol, 3) != 0){
  473. writerr(conn, "verifier syntax error");
  474. goto done;
  475. }
  476. hexmu = mess+3;
  477. *eol = 0;
  478. ks = eol+3;
  479. eol = strchr(ks, '\n');
  480. if(!eol || strncmp("\nS=", eol, 3) != 0){
  481. writerr(conn, "verifier syntax error for secstore 1.0");
  482. goto done;
  483. }
  484. *eol = 0;
  485. S = eol+3;
  486. eol = strchr(S, '\n');
  487. if(!eol){
  488. writerr(conn, "verifier syntax error for secstore 1.0");
  489. goto done;
  490. }
  491. *eol = 0;
  492. if(pS)
  493. *pS = estrdup(S);
  494. strtomp(hexmu, nil, 64, mu);
  495. mpexp(mu, x, pak->p, sigma);
  496. hexsigma = mptoa(sigma, 64, nil, 0);
  497. shorthash("server", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  498. enc64(kc, sizeof kc, digest, SHA1dlen);
  499. if(strcmp(ks, kc) != 0){
  500. writerr(conn, "verifier didn't match");
  501. goto done;
  502. }
  503. // send hash2(g**xy)
  504. shorthash("client", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  505. enc64(kc, sizeof kc, digest, SHA1dlen);
  506. snprint(mess2, Maxmsg, "k'=%s\n", kc);
  507. conn->write(conn, (uint8_t*)mess2, strlen(mess2));
  508. // set session key
  509. shorthash("session", C, S, hexm, hexmu, hexsigma, hexHi, digest);
  510. memset(hexsigma, 0, strlen(hexsigma));
  511. n = conn->secret(conn, digest, 0);
  512. memset(digest, 0, SHA1dlen);
  513. if(n < 0){//assert
  514. writerr(conn, "can't set secret");
  515. goto done;
  516. }
  517. rc = 0;
  518. done:
  519. mpfree(x);
  520. mpfree(sigma);
  521. mpfree(mu);
  522. mpfree(m);
  523. mpfree(Hi);
  524. mpfree(H);
  525. free(hexsigma);
  526. free(hexHi);
  527. free(hexm);
  528. free(mess);
  529. return rc;
  530. }
  531. int
  532. secstorefetch(char *password)
  533. {
  534. int rv = -1, fd;
  535. char s[Maxmsg+1];
  536. SConn *conn;
  537. char *pass, *sta;
  538. sta = nil;
  539. conn = nil;
  540. if(password != nil && *password)
  541. pass = estrdup(password);
  542. else
  543. pass = readcons("secstore password", nil, 1);
  544. if(pass==nil || strlen(pass)==0){
  545. werrstr("cancel");
  546. goto Out;
  547. }
  548. if((fd = secdial()) < 0)
  549. goto Out;
  550. if((conn = newSConn(fd)) == nil)
  551. goto Out;
  552. if(PAKclient(conn, owner, pass, nil) < 0){
  553. werrstr("password mistyped?");
  554. goto Out;
  555. }
  556. if(readstr(conn, s) < 0)
  557. goto Out;
  558. if(strcmp(s, "STA") == 0){
  559. sta = readcons("STA PIN+SecureID", nil, 1);
  560. if(sta==nil || strlen(sta)==0){
  561. werrstr("cancel");
  562. goto Out;
  563. }
  564. if(strlen(sta) >= sizeof s - 3){
  565. werrstr("STA response too long");
  566. goto Out;
  567. }
  568. strcpy(s+3, sta);
  569. conn->write(conn, (uint8_t*)s, strlen(s));
  570. readstr(conn, s);
  571. }
  572. if(strcmp(s, "OK") !=0){
  573. werrstr("%s", s);
  574. goto Out;
  575. }
  576. if(getfile(conn, (uint8_t*)pass, strlen(pass)) < 0)
  577. goto Out;
  578. conn->write(conn, (uint8_t*)"BYE", 3);
  579. rv = 0;
  580. Out:
  581. if(conn)
  582. conn->free(conn);
  583. if(pass)
  584. free(pass);
  585. if(sta)
  586. free(sta);
  587. return rv;
  588. }