diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 17:07:39 +0000 |
| commit | 37da2899f40661e3e9631e497da8dc59b971cbd0 (patch) | |
| tree | cbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/login.b | |
| parent | 54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff) | |
20060303a
Diffstat (limited to 'appl/lib/login.b')
| -rw-r--r-- | appl/lib/login.b | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/appl/lib/login.b b/appl/lib/login.b new file mode 100644 index 00000000..2feb3f6a --- /dev/null +++ b/appl/lib/login.b @@ -0,0 +1,175 @@ +# Inferno Encrypt Key Exchange Protocol +# +# Copyright © 1995-1999 Lucent Techologies Inc. All rights reserved. +# +# This code uses methods that are subject to one or more patents +# held by Lucent Technologies Inc. Its use outside Inferno +# requires a separate licence from Lucent. +# +implement Login; + +include "sys.m"; + sys: Sys; + +include "keyring.m"; + kr: Keyring; + IPint: import kr; + +include "security.m"; + +include "string.m"; + +# see login(6) +login(id, password, dest: string): (string, ref Keyring->Authinfo) +{ + sys = load Sys Sys->PATH; + kr = load Keyring Keyring->PATH; + if(kr == nil) + return nomod(Keyring->PATH); + + ssl := load SSL SSL->PATH; + if(ssl == nil) + return nomod(SSL->PATH); + + rand := load Random Random->PATH; + if(rand == nil) + return nomod(Random->PATH); + + if(dest == nil) + dest = "$SIGNER"; + for(j:=0; j<len dest && dest[j] != '!'; j++) + break; + if(j >= len dest) + dest = "net!"+dest+"!inflogin"; # BUG: must do better + + (ok, lc) := sys->dial(dest, nil); + if(ok < 0) + return (sys->sprint("can't contact login service: %r"), nil); + + # push ssl, leave in clear mode for now + (err, c) := ssl->connect(lc.dfd); + if(c == nil) + return ("can't push ssl: " + err, nil); + lc.dfd = nil; + lc.cfd = nil; + + # user->CA name + if(kr->putstring(c.dfd, id) < 0) + return (sys->sprint("can't send user name: %r"), nil); + + # CA->user ACK + (s, why) := kr->getstring(c.dfd); + if(why != nil) + return ("remote: " + why, nil); + if(s != id) + return ("unexpected reply from signer: " + s, nil); + + # user->CA ivec + ivec := rand->randombuf(rand->ReallyRandom, 8); + if(kr->putbytearray(c.dfd, ivec, len ivec) < 0) + return (sys->sprint("can't send initialization vector: %r"), nil); + + # start encrypting + pwbuf := array of byte password; + digest := array[Keyring->SHA1dlen] of byte; + kr->sha1(pwbuf, len pwbuf, digest, nil); + pwbuf = array[8] of byte; + for(i := 0; i < 8; i++) + pwbuf[i] = digest[i] ^ digest[8+i]; + for(i = 0; i < 4; i++) + pwbuf[i] ^= digest[16+i]; + for(i = 0; i < 8; i++) + pwbuf[i] ^= ivec[i]; + err = ssl->secret(c, pwbuf, pwbuf); + if(err != nil) + return ("can't set secret: " + err, nil); + if(sys->fprint(c.cfd, "alg rc4") < 0) + return (sys->sprint("can't push alg rc4: %r"), nil); + #if(sys->fprint(c.cfd, "alg desebc") < 0) + # return (sys->sprint("can't push alg desecb: %r"), nil); + + # CA -> user key(alpha**r0 mod p) + (s, err) = kr->getstring(c.dfd); + if(err != nil){ + if(err == "failure") # calculated secret is wrong + return ("name or secret incorrect (alpha**r0 mod p)", nil); + return ("remote:" + err, nil); + } + + # stop encrypting + if(sys->fprint(c.cfd, "alg clear") < 0) + return (sys->sprint("can't push alg clear: %r"), nil); + alphar0 := IPint.b64toip(s); + + # CA->user alpha + (s, err) = kr->getstring(c.dfd); + if(err != nil){ + if(err == "failure") + return ("name or secret incorrect (alpha)", nil); + return ("remote: " + err, nil); + } + info := ref Keyring->Authinfo; + info.alpha = IPint.b64toip(s); + + # CA->user p + (s, err) = kr->getstring(c.dfd); + if(err != nil){ + if(err == "failure") + return ("name or secret incorrect (p)", nil); + return ("remote: " + err, nil); + } + info.p = IPint.b64toip(s); + + # sanity check + bits := info.p.bits(); + abits := info.alpha.bits(); + if(abits > bits || abits < 2) + return ("bogus diffie hellman constants", nil); + + # generate our random diffie hellman part + r1 := kr->IPint.random(bits/4, bits); + alphar1 := info.alpha.expmod(r1, info.p); + + # user->CA alpha**r1 mod p + if(kr->putstring(c.dfd, alphar1.iptob64()) < 0) + return (sys->sprint("can't send (alpha**r1 mod p): %r"), nil); + + # compute alpha**(r0*r1) mod p + alphar0r1 := alphar0.expmod(r1, info.p); + + # turn on digesting + secret := alphar0r1.iptobytes(); + err = ssl->secret(c, secret, secret); + if(err != nil) + return ("can't set digesting: " + err, nil); + if(sys->fprint(c.cfd, "alg sha1") < 0) + return (sys->sprint("can't push alg sha1: %r"), nil); + + # CA->user CA's public key, SHA(CA's public key + secret) + (s, err) = kr->getstring(c.dfd); + if(err != nil) + return ("can't get signer's public key: " + err, nil); + + info.spk = kr->strtopk(s); + + # generate a key pair + info.mysk = kr->genSKfromPK(info.spk, id); + info.mypk = kr->sktopk(info.mysk); + + # user->CA user's public key, SHA(user's public key + secret) + if(kr->putstring(c.dfd, kr->pktostr(info.mypk)) < 0) + return (sys->sprint("can't send your public: %r"), nil); + + # CA->user user's public key certificate + (s, err) = kr->getstring(c.dfd); + if(err != nil) + return ("can't get certificate: " + err, nil); + + info.cert = kr->strtocert(s); + return(nil, info); +} + +nomod(mod: string): (string, ref Keyring->Authinfo) +{ + return (sys->sprint("can't load module %s: %r", mod), nil); +} |
