summaryrefslogtreecommitdiff
path: root/appl/lib/login.b
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 17:07:39 +0000
commit37da2899f40661e3e9631e497da8dc59b971cbd0 (patch)
treecbc6d4680e347d906f5fa7fca73214418741df72 /appl/lib/login.b
parent54bc8ff236ac10b3eaa928fd6bcfc0cdb2ba46ae (diff)
20060303a
Diffstat (limited to 'appl/lib/login.b')
-rw-r--r--appl/lib/login.b175
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);
+}