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