diff options
Diffstat (limited to 'appl/cmd/auth/factotum/proto')
| -rw-r--r-- | appl/cmd/auth/factotum/proto/infauth.b | 362 | ||||
| -rw-r--r-- | appl/cmd/auth/factotum/proto/keyreps.b | 173 | ||||
| -rw-r--r-- | appl/cmd/auth/factotum/proto/keyreps.m | 23 | ||||
| -rw-r--r-- | appl/cmd/auth/factotum/proto/mkfile | 22 | ||||
| -rw-r--r-- | appl/cmd/auth/factotum/proto/p9any.b | 232 | ||||
| -rw-r--r-- | appl/cmd/auth/factotum/proto/pass.b | 29 |
6 files changed, 841 insertions, 0 deletions
diff --git a/appl/cmd/auth/factotum/proto/infauth.b b/appl/cmd/auth/factotum/proto/infauth.b new file mode 100644 index 00000000..244979bc --- /dev/null +++ b/appl/cmd/auth/factotum/proto/infauth.b @@ -0,0 +1,362 @@ +implement Authproto; + +include "sys.m"; + sys: Sys; +include "draw.m"; +include "keyring.m"; + keyring: Keyring; + IPint: import keyring; + SK, PK, Certificate, DigestState: import Keyring; +include "security.m"; +include "bufio.m"; +include "sexprs.m"; + sexprs: Sexprs; + Sexp: import sexprs; +include "spki.m"; + spki: SPKI; +include "daytime.m"; + daytime: Daytime; +include "keyreps.m"; + keyreps: Keyreps; + Keyrep: import keyreps; +include "../authio.m"; + authio: Authio; + Aattr, Aval, Aquery: import Authio; + Attr, IO, Key, Authinfo: import authio; + +# at end of authentication, sign a hash of the authenticated username and +# a secret known only to factotum. that certificate can act as +# a later proof that this factotum has authenticated that user, +# and hence factotum will disclose certificates that allow disclosure +# only to that username. + +Debug: con 0; + +Maxmsg: con 4000; + +Error0, Error1: exception(string); + +init(f: Authio): string +{ + authio = f; + sys = load Sys Sys->PATH; + spki = load SPKI SPKI->PATH; + spki->init(); + sexprs = load Sexprs Sexprs->PATH; + sexprs->init(); + keyring = load Keyring Keyring->PATH; + daytime = load Daytime Daytime->PATH; + keyreps = load Keyreps Keyreps->PATH; + keyreps->init(); + return nil; +} + +interaction(attrs: list of ref Attr, io: ref IO): string +{ + ai: ref Authinfo; + (key, err) := io.findkey(attrs, "proto=infauth"); + if(key == nil) + return err; + info: ref Keyring->Authinfo; + (info, err) = keytoauthinfo(key); + if(info == nil) + return err; + anysigner := int authio->lookattrval(key.attrs, "anysigner"); + rattrs: list of ref Sexp; + { + # send auth protocol version number + sendmsg(io, array of byte "1"); + + # get auth protocol version number + if(int string getmsg(io) != 1) + raise Error0("incompatible authentication protocol"); + + # generate alpha**r0 + p := info.p; + low := p.shr(p.bits()/4); + r0 := rand(low, p, Random->NotQuiteRandom); + αr0 := info.alpha.expmod(r0, p); + # trim(αr0); the IPint library should do this for us, i think. + + # send alpha**r0 mod p, mycert, and mypk + sendmsg(io, array of byte αr0.iptob64()); + sendmsg(io, array of byte keyring->certtostr(info.cert)); + sendmsg(io, array of byte keyring->pktostr(info.mypk)); + + # get alpha**r1 mod p, hiscert, hispk + αr1 := IPint.b64toip(string getmsg(io)); + + # trying a fast one + if(p.cmp(αr1) <= 0) + raise Error0("implausible parameter value"); + + # if alpha**r1 == alpha**r0, someone may be trying a replay + if(αr0.eq(αr1)) + raise Error0("possible replay attack"); + + hiscert := keyring->strtocert(string getmsg(io)); + if(hiscert == nil && !anysigner) + raise Error0(sys->sprint("bad certificate: %r")); + + buf := getmsg(io); + hispk := keyring->strtopk(string buf); + if(!anysigner){ + # verify their public key + if(verify(info.spk, hiscert, buf) == 0) + raise Error0("pk doesn't match certificate"); # likely the signers don't match. + + # check expiration date - in seconds of epoch + if(hiscert.exp != 0 && hiscert.exp <= now()) + raise Error0("certificate expired"); + } + buf = nil; + + # sign alpha**r0 and alpha**r1 and send + αcert := sign(info.mysk, "sha", 0, array of byte (αr0.iptob64() + αr1.iptob64())); + sendmsg(io, array of byte keyring->certtostr(αcert)); + + # get signature of alpha**r1 and alpha**r0 and verify + αcert = keyring->strtocert(string getmsg(io)); + if(αcert == nil) + raise Error0("alpha**r1 doesn't match certificate"); + + if(verify(hispk, αcert, array of byte (αr1.iptob64() + αr0.iptob64())) == 0) + raise Error0(sys->sprint("bad certificate: %r")); + + ai = ref Authinfo; + # we are now authenticated and have a common secret, alpha**(r0*r1) + if(!anysigner) + rattrs = sl(ss("signer") :: principal(info.spk) :: nil) :: rattrs; + rattrs = sl(ss("remote-pk") :: principal(hispk) :: nil) :: rattrs; + rattrs = sl(ss("local-pk") :: principal(info.mypk) :: nil) :: rattrs; + rattrs = sl(ss("secret") :: sb(αr1.expmod(r0, p).iptobytes()) :: nil) :: rattrs; + ai.suid = hispk.owner; + ai.cuid = info.mypk.owner; + sendmsg(io, array of byte "OK"); + }exception e{ + Error0 => + err = e; + senderr(io, e); + break; + Error1 => + senderr(io, "missing your authentication data"); + x: string = e; + return "remote: "+x; + } + + { + while(string getmsg(io) != "OK") + ; + }exception e{ + Error0 => + return e; + Error1 => + x: string = e; + return "remote: "+x; + } + if(err != nil) + return err; + + return negotiatecrypto(io, key, ai, rattrs); +} + +negotiatecrypto(io: ref IO, key: ref Key, ai: ref Authinfo, attrs: list of ref Sexp): string +{ + role := authio->lookattrval(key.attrs, "role"); + alg: string; + { + if(role == "client"){ + alg = authio->lookattrval(key.attrs, "alg"); + if(alg == nil) + alg = "md5/rc4_256"; + sendmsg(io, array of byte alg); + }else if(role == "server"){ + alg = string getmsg(io); + if(!algcompatible(alg, sys->tokenize(authio->lookattrval(key.attrs, "algs"), " ").t1)) + raise Error0("unsupported client algorithm"); + } + }exception e{ + Error0 or + Error1 => + return e; + } + + if(alg != nil) + attrs = sl(ss("alg") :: ss(alg) :: nil) :: attrs; + ai.secret = sl(attrs).pack(); + + io.done(ai); + return nil; +} + +algcompatible(nil: string, nil: list of string): int +{ + return 1; # XXX +} + +principal(pk: ref Keyring->PK): ref Sexp +{ + return spki->(Keyrep.pk(pk).mkkey()).sexp(); +} + +ipint(i: int): ref IPint +{ + return IPint.inttoip(i); +} + +rand(p, q: ref IPint, nil: int): ref IPint +{ + if(p.cmp(q) > 0) + (p, q) = (q, p); + diff := q.sub(p); + q = nil; + if(diff.cmp(ipint(2)) < 0){ + sys->print("rand range must be at least 2"); + return IPint.inttoip(0); + } + l := diff.bits(); + T := ipint(1).shl(l); + l = ((l + 7) / 8) * 8; + slop := T.div(diff).t1; + r: ref IPint; + do{ + r = IPint.random(0, l); + }while(r.cmp(slop) < 0); + r = r.div(diff).t1.add(p); + return r; +} + +now(): int +{ + return daytime->now(); +} + +Hashfn: type ref fn(a: array of byte, alen: int, digest: array of byte, state: ref DigestState): ref DigestState; + +hashalg(ha: string): Hashfn +{ + case ha { + "sha" or + "sha1" => + return keyring->sha1; + "md4" => + return keyring->md4; + "md5" => + return keyring->md5; + } + return nil; +} + +sign(sk: ref SK, ha: string, exp: int, buf: array of byte): ref Certificate +{ + state := hashalg(ha)(buf, len buf, nil, nil); + return keyring->sign(sk, exp, state, ha); +} + +verify(pk: ref PK, cert: ref Certificate, buf: array of byte): int +{ + state := hashalg(cert.ha)(buf, len buf, nil, nil); + return keyring->verify(pk, cert, state); +} + +getmsg(io: ref IO): array of byte raises (Error0, Error1) +{ + while((buf := io.read()) == nil || (n := len buf) < 5) + io.toosmall(5); + if(len buf != 5) + raise Error0("io error: (impossible?) msg length " + string n); + h := string buf; + if(h[0] == '!') + m := int h[1:]; + else + m = int h; + while((buf = io.read()) == nil || (n = len buf) < m) + io.toosmall(m); + if(len buf != m) + raise Error0("io error: (impossible?) msg length " + string m); + if(h[0] == '!'){ +sys->print("got remote error: %s, len %d\n", string buf, len string buf); + raise Error1(string buf); + } + return buf; +} + +sendmsg(io: ref IO, buf: array of byte) +{ + h := sys->aprint("%4.4d\n", len buf); + io.write(h, len h); + io.write(buf, len buf); +} + +senderr(io: ref IO, e: string) +{ + buf := array of byte e; + h := sys->aprint("!%3.3d\n", len buf); + io.write(h, len h); + io.write(buf, len buf); +} + +keytoauthinfo(key:ref Key): (ref Keyring->Authinfo, string) +{ + if((s := authio->lookattrval(key.secrets, "!authinfo")) == nil){ + # XXX could look up authinfo by hash at this point + return (nil, "no authinfo attribute"); + } + + return strtoauthinfo(s); +} + +strtoauthinfo(s: string): (ref Keyring->Authinfo, string) +{ + (se, err, nil) := Sexp.parse(s); + if(se == nil) + return (nil, err); + els := se.els(); + if(len els != 5) + return (nil, "bad authinfo contents"); + ai := ref Keyring->Authinfo; + if((ai.spk = keyring->strtopk((hd els).astext())) == nil) + return (nil, "bad signer public key"); + els = tl els; + if((ai.cert = keyring->strtocert((hd els).astext())) == nil) + return (nil, "bad certificate"); + els = tl els; + if((ai.mysk = keyring->strtosk((hd els).astext())) == nil) + return (nil, "bad secret/public key"); + if((ai.mypk = keyring->sktopk(ai.mysk)) == nil) + return (nil, "cannot make pk from sk"); + els = tl els; + if((ai.alpha = IPint.bytestoip((hd els).asdata())) == nil) + return (nil, "bad value for alpha"); + els = tl els; + if((ai.p = IPint.bytestoip((hd els).asdata())) == nil) + return (nil, "bad value for p"); + return (ai, nil); +} + +authinfotostr(ai: ref Keyring->Authinfo): string +{ + return (ref Sexp.List( + ss(keyring->pktostr(ai.spk)) :: + ss(keyring->certtostr(ai.cert)) :: + ss(keyring->sktostr(ai.mysk)) :: + sb(ai.alpha.iptobytes()) :: + sb(ai.p.iptobytes()) :: + nil + )).b64text(); +} + +ss(s: string): ref Sexp.String +{ + return ref Sexp.String(s, nil); +} + +sb(d: array of byte): ref Sexp.Binary +{ + return ref Sexp.Binary(d, nil); +} + +sl(l: list of ref Sexp): ref Sexp +{ + return ref Sexp.List(l); +} diff --git a/appl/cmd/auth/factotum/proto/keyreps.b b/appl/cmd/auth/factotum/proto/keyreps.b new file mode 100644 index 00000000..5fdac2c0 --- /dev/null +++ b/appl/cmd/auth/factotum/proto/keyreps.b @@ -0,0 +1,173 @@ +implement Keyreps; +include "sys.m"; + sys: Sys; +include "keyring.m"; + kr: Keyring; + IPint: import kr; +include "sexprs.m"; +include "spki.m"; +include "encoding.m"; + base64: Encoding; +include "keyreps.m"; + +init() +{ + sys = load Sys Sys->PATH; + kr = load Keyring Keyring->PATH; + base64 = load Encoding Encoding->BASE64PATH; +} + +keyextract(flds: list of string, names: list of (string, int)): list of (string, ref IPint) +{ + a := array[len flds] of ref IPint; + for(i := 0; i < len a; i++){ + a[i] = IPint.b64toip(hd flds); + flds = tl flds; + } + rl: list of (string, ref IPint); + for(; names != nil; names = tl names){ + (n, p) := hd names; + if(p < len a) + rl = (n, a[p]) :: rl; + } + return revt(rl); +} + +Keyrep.pk(pk: ref Keyring->PK): ref Keyrep.PK +{ + s := kr->pktostr(pk); + (nf, flds) := sys->tokenize(s, "\n"); + if((nf -= 2) < 0) + return nil; + case hd flds { + "rsa" => + return ref Keyrep.PK(hd flds, hd tl flds, + keyextract(tl tl flds, list of {("e",1), ("n",0)})); + "elgamal" or "dsa" => + return ref Keyrep.PK(hd flds, hd tl flds, + keyextract(tl tl flds, list of {("p",0), ("alpha",1), ("key",2)})); + * => + return nil; + } +} + +Keyrep.sk(pk: ref Keyring->SK): ref Keyrep.SK +{ + s := kr->pktostr(pk); + (nf, flds) := sys->tokenize(s, "\n"); + if((nf -= 2) < 0) + return nil; + case hd flds { + "rsa" => + return ref Keyrep.SK(hd flds, hd tl flds, + keyextract(tl tl flds,list of {("e",1), ("n",0), ("!dk",2), ("!p",3), ("!q",4), ("!kp",5), ("!kq",6), ("!c2",7)})); + "elgamal" or "dsa" => + return ref Keyrep.SK(hd flds, hd tl flds, + keyextract(tl tl flds, list of {("p",0), ("alpha",1), ("key",2), ("!secret",3)})); + * => + return nil; + } +} + +Keyrep.get(k: self ref Keyrep, n: string): ref IPint +{ + for(el := k.els; el != nil; el = tl el) + if((hd el).t0 == n) + return (hd el).t1; + return nil; +} + +Keyrep.getb(k: self ref Keyrep, n: string): array of byte +{ + v := k.get(n); + if(v == nil) + return nil; + return pre0(v.iptobebytes()); +} + +pre0(a: array of byte): array of byte +{ + for(i:=0; i<len a-1; i++) + if(a[i] != a[i+1] && (a[i] != byte 0 || (int a[i+1] & 16r80) != 0)) + break; + if(i > 0) + a = a[i:]; + if(len a < 1 || (int a[0] & 16r80) == 0) + return a; + b := array[len a + 1] of byte; + b[0] = byte 0; + b[1:] = a; + return b; +} + +Keyrep.mkpk(k: self ref Keyrep): (ref Keyring->PK, int) +{ + case k.alg { + "rsa" => + e := k.get("e"); + n := k.get("n"); + return (kr->strtopk(sys->sprint("rsa\n%s\n%s\n%s\n", k.owner, n.iptob64(), e.iptob64())), n.bits()); + * => + raise "Keyrep: unknown algorithm" + k.alg; + } +} + +Keyrep.mksk(k: self ref Keyrep): ref Keyring->SK +{ + case k.alg { + "rsa" => + e := k.get("e"); + n := k.get("n"); + dk := k.get("!dk"); + p := k.get("!p"); + q := k.get("!q"); + kp := k.get("!kp"); + kq := k.get("!kq"); + c12 := k.get("!c2"); + return kr->strtosk(sys->sprint("rsa\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + k.owner, n.iptob64(), e.iptob64(), dk.iptob64(), p.iptob64(), q.iptob64(), + kp.iptob64(), kq.iptob64(), c12.iptob64())); + * => + raise "Keyrep: unknown algorithm"; + } +} + +Keyrep.eq(k1: self ref Keyrep, k2: ref Keyrep): int +{ + # n but n is small + for(l1 := k1.els; l1 != nil; l1 = tl l1){ + (n, v1) := hd l1; + v2 := k2.get(n); + if(v2 == nil || !v1.eq(v2)) + return 0; + } + for(l2 := k2.els; l2 != nil; l2 = tl l2) + if(k1.get((hd l2).t0) == nil) + return 0; + return 1; +} + +Keyrep.mkkey(kr: self ref Keyrep): ref SPKI->Key +{ + k := ref SPKI->Key; + (k.pk, k.nbits) = kr.mkpk(); + k.sk = kr.mksk(); + return k; +} + +sig2icert(sig: ref SPKI->Signature, signer: string, exp: int): ref Keyring->Certificate +{ + if(sig.sig == nil) + return nil; + s := sys->sprint("%s\n%s\n%s\n%d\n%s\n", "rsa", sig.hash.alg, signer, exp, base64->enc((hd sig.sig).t1)); +#sys->print("alg %s *** %s\n", sig.sa, base64->enc((hd sig.sig).t1)); + return kr->strtocert(s); +} + +revt[S,T](l: list of (S,T)): list of (S,T) +{ + rl: list of (S,T); + for(; l != nil; l = tl l) + rl = hd l :: rl; + return rl; +} diff --git a/appl/cmd/auth/factotum/proto/keyreps.m b/appl/cmd/auth/factotum/proto/keyreps.m new file mode 100644 index 00000000..ddfd7f0d --- /dev/null +++ b/appl/cmd/auth/factotum/proto/keyreps.m @@ -0,0 +1,23 @@ +Keyreps: module +{ + PATH: con "/dis/lib/spki/keyreps.dis"; + init: fn(); + Keyrep: adt { + alg: string; + owner: string; + els: list of (string, ref Keyring->IPint); + pick{ # keeps a type distance between public and private keys + PK => + SK => + } + + pk: fn(pk: ref Keyring->PK): ref Keyrep.PK; + sk: fn(sk: ref Keyring->SK): ref Keyrep.SK; + mkpk: fn(k: self ref Keyrep): (ref Keyring->PK, int); + mksk: fn(k: self ref Keyrep): ref Keyring->SK; + get: fn(k: self ref Keyrep, n: string): ref Keyring->IPint; + getb: fn(k: self ref Keyrep, n: string): array of byte; + eq: fn(k1: self ref Keyrep, k2: ref Keyrep): int; + mkkey: fn(k: self ref Keyrep): ref SPKI->Key; + }; +}; diff --git a/appl/cmd/auth/factotum/proto/mkfile b/appl/cmd/auth/factotum/proto/mkfile new file mode 100644 index 00000000..efdd73da --- /dev/null +++ b/appl/cmd/auth/factotum/proto/mkfile @@ -0,0 +1,22 @@ +<../../../../../mkconfig + +TARG=\ + p9any.dis\ + pass.dis\ + +SYSMODULES=\ + factotum.m\ + keyring.m\ + security.m\ + rand.m\ + sys.m\ + draw.m\ + bufio.m\ + string.m\ + +MODULES=\ + ../authio.m\ + +DISBIN=$ROOT/dis/auth/proto + +<$ROOT/mkfiles/mkdis diff --git a/appl/cmd/auth/factotum/proto/p9any.b b/appl/cmd/auth/factotum/proto/p9any.b new file mode 100644 index 00000000..1668a701 --- /dev/null +++ b/appl/cmd/auth/factotum/proto/p9any.b @@ -0,0 +1,232 @@ +implement Authproto; + +# currently includes p9sk1 + +include "sys.m"; + sys: Sys; + Rread, Rwrite: import Sys; + +include "draw.m"; + +include "keyring.m"; + kr: Keyring; + +include "auth9.m"; + auth9: Auth9; + ANAMELEN, AERRLEN, DOMLEN, DESKEYLEN, CHALLEN, SECRETLEN: import Auth9; + TICKREQLEN, TICKETLEN, AUTHENTLEN: import Auth9; + Ticketreq, Ticket, Authenticator: import auth9; + +include "../authio.m"; + authio: Authio; + Aattr, Aval, Aquery: import Authio; + Attr, IO, Key, Authinfo: import authio; + netmkaddr, eqbytes, memrandom: import authio; + +include "encoding.m"; + base16: Encoding; + +Debug: con 0; + +# init, addkey, closekey, write, read, close, keyprompt + +init(f: Authio): string +{ + authio = f; + sys = load Sys Sys->PATH; + kr = load Keyring Keyring->PATH; + auth9 = load Auth9 Auth9->PATH; + auth9->init(); + base16 = load Encoding Encoding->BASE16PATH; + return nil; +} + +version := 1; + +interaction(attrs: list of ref Attr, io: ref IO): string +{ + return p9any(io); +} + +p9any(io: ref IO): string +{ + while((buf := io.read()) == nil || (n := len buf) == 0 || buf[n-1] != byte 0) + io.toosmall(2048); + s := string buf[0:n-1]; + if(Debug) + sys->print("s: %q\n", s); + (nil, flds) := sys->tokenize(s, " \t"); + if(flds != nil && len hd flds >= 2 && (hd flds)[0:2] == "v."){ + if(hd flds == "v.2"){ + version = 2; + flds = tl flds; + if(Debug) + sys->print("version 2\n"); + }else + return "p9any: unknown version"; + } + doms: list of string; + for(; flds != nil; flds = tl flds){ + (nf, subf) := sys->tokenize(hd flds, "@"); + if(nf == 2 && hd subf == "p9sk1") + doms = hd tl subf :: doms; + } + if(doms == nil) + return "p9any: unsupported protocol"; + if(Debug){ + for(l := doms; l != nil; l = tl l) + sys->print("dom: %q\n", hd l); + } + r := array of byte ("p9sk1 "+hd doms); + buf[0:] = r; + buf[len r] = byte 0; + io.write(buf, len r + 1); + if(version == 2){ + b := io.readn(3); + if(b == nil || b[0] != byte 'O' || b[1] != byte 'K' || b[2] != byte 0) + return "p9any: AS protocol botch: not OK"; + if(Debug) + sys->print("OK\n"); + } + return p9sk1client(io, hd doms); +} + +#p9sk1: +# C->S: nonce-C +# S->C: nonce-S, uid-S, domain-S +# C->A: nonce-S, uid-S, domain-S, uid-C, factotum-C +# A->C: Kc{nonce-S, uid-C, uid-S, Kn}, Ks{nonce-S, uid-C, uid-S, K-n} +# C->S: Ks{nonce-S, uid-C, uid-S, K-n}, Kn{nonce-S, counter} +# S->C: Kn{nonce-C, counter} + +#asserts that uid-S and uid-C share new secret Kn +#increment the counter to reuse the ticket. + +p9sk1client(io: ref IO, udom: string): string +{ + + # C->S: nonce-C + cchal := array[CHALLEN] of byte; + memrandom(cchal, CHALLEN); + if(io.write(cchal, len cchal) != len cchal) + return sys->sprint("p9sk1: can't write cchal: %r"); + + # S->C: nonce-S, uid-S, domain-S + trbuf := io.readn(TICKREQLEN); + if(trbuf == nil) + return sys->sprint("p9sk1: can't read ticketreq: %r"); + + (nil, tr) := Ticketreq.unpack(trbuf); + if(tr == nil) + return "p9sk1: can't unpack ticket request"; + if(Debug) + sys->print("ticketreq: type=%d authid=%q authdom=%q chal= hostid=%q uid=%q\n", + tr.rtype, tr.authid, tr.authdom, tr.hostid, tr.uid); + + (mykey, diag) := io.findkey(nil, sys->sprint("dom=%q proto=p9sk1 user? !password?", udom)); + if(mykey == nil) + return "can't find key: "+diag; + ukey: array of byte; + if((a := authio->lookattrval(mykey.secrets, "!hex")) != nil){ + ukey = base16->dec(a); + if(len ukey != DESKEYLEN) + return "p9sk1: invalid !hex key"; + }else if((a = authio->lookattrval(mykey.secrets, "!password")) != nil) + ukey = auth9->passtokey(a); + else + return "no !password (or !hex) in key"; + + # A->C: Kc{nonce-S, uid-C, uid-S, Kn}, Ks{nonce-S, uid-C, uid-S, K-n} + user := authio->lookattrval(mykey.attrs, "user"); + if(user == nil) + user = authio->user(); # shouldn't happen + tr.rtype = Auth9->AuthTreq; + tr.hostid = user; + tr.uid = tr.hostid; # not speaking for anyone else + (tick, serverbits) := getastickets(tr, ukey); + if(tick == nil) + return sys->sprint("p9sk1: getasticket failed: %r"); + if(tick.num != Auth9->AuthTc) + return "p9sk1: getasticket: failed: wrong key?"; + if(Debug) + sys->print("ticket: num=%d chal= cuid=%q suid=%q key=\n", tick.num, tick.cuid, tick.suid); + + # C->S: Ks{nonce-S, uid-C, uid-S, K-n}, Kn{nonce-S, counter} + ar := ref Authenticator; + ar.num = Auth9->AuthAc; + ar.chal = tick.chal; + ar.id = 0; + obuf := array[TICKETLEN+AUTHENTLEN] of byte; + obuf[0:] = serverbits; + obuf[TICKETLEN:] = ar.pack(tick.key); + if(io.write(obuf, len obuf) != len obuf) + return "p9sk1: error writing authenticator: %r"; + + # S->C: Kn{nonce-C, counter} + sbuf := io.readn(AUTHENTLEN); + if(sbuf == nil) + return sys->sprint("p9sk1: can't read server's authenticator: %r"); + (nil, ar) = Authenticator.unpack(sbuf, tick.key); + if(ar.num != Auth9->AuthAs || !eqbytes(ar.chal, cchal) || ar.id != 0) + return "invalid authenticator from server"; + + ai := ref Authinfo(tick.cuid, tick.suid, nil, auth9->des56to64(tick.key)); + io.done(ai); + + return nil; +} + +getastickets(tr: ref Ticketreq, key: array of byte): (ref Ticket, array of byte) +{ + afd := authdial(nil, tr.authdom); + if(afd == nil) + return (nil, nil); + return auth9->_asgetticket(afd, tr, key); +} + +# +# where to put the following functions? +# + +csgetvalue(netroot: string, keytag: string, keyval: string, needtag: string): string +{ + cs := "/net/cs"; + if(netroot != nil) + cs = netroot+"/cs"; + fd := sys->open(cs, Sys->ORDWR); # TO DO: choice of root + if(fd == nil) + return nil; + if(sys->fprint(fd, "!%s=%s %s=*", keytag, keyval, needtag) < 0) + return nil; + sys->seek(fd, big 0, 0); + buf := array[1024] of byte; + while((n := sys->read(fd, buf, len buf)) > 0){ + al := authio->parseline(string buf[0:n]); # assume the conventions match factotum's + for(; al != nil; al = tl al) + if((hd al).name == needtag) + return (hd al).val; + } + return nil; +} + +authdial(netroot: string, dom: string): ref Sys->FD +{ + p: string; + if(dom != nil){ + # look up an auth server in an authentication domain + p = csgetvalue(netroot, "authdom", dom, "auth"); + + # if that didn't work, just try the IP domain + if(p == nil) + p = csgetvalue(netroot, "dom", dom, "auth"); + if(p == nil) + p = "$auth"; # temporary ... + if(p == nil){ + sys->werrstr("no auth server found for "+dom); + return nil; + } + }else + p = "$auth"; # look for one relative to my machine + (nil, conn) := sys->dial(netmkaddr(p, netroot, "ticket"), nil); + return conn.dfd; +} diff --git a/appl/cmd/auth/factotum/proto/pass.b b/appl/cmd/auth/factotum/proto/pass.b new file mode 100644 index 00000000..9c4462b3 --- /dev/null +++ b/appl/cmd/auth/factotum/proto/pass.b @@ -0,0 +1,29 @@ +implement Authproto; + +include "sys.m"; + sys: Sys; + +include "../authio.m"; + authio: Authio; + Attr, IO: import authio; + +init(f: Authio): string +{ + sys = load Sys Sys->PATH; + authio = f; + return nil; +} + +interaction(attrs: list of ref Attr, io: ref Authio->IO): string +{ + (key, err) := io.findkey(attrs, "user? !password?"); + if(key == nil) + return err; + user := authio->lookattrval(key.attrs, "user"); + if(user == nil) + return "unknown user"; + pass := authio->lookattrval(key.secrets, "!password"); + a := sys->aprint("%q %q", user, pass); + io.write(a, len a); + return nil; +} |
