1# Inferno Encrypt Key Exchange Protocol 2# 3# Copyright © 1995-1999 Lucent Techologies Inc. All rights reserved. 4# 5# This code uses methods that are subject to one or more patents 6# held by Lucent Technologies Inc. Its use outside Inferno 7# requires a separate licence from Lucent. 8# 9implement Login; 10 11include "sys.m"; 12 sys: Sys; 13 14include "keyring.m"; 15 kr: Keyring; 16 IPint: import kr; 17 18include "security.m"; 19 20include "dial.m"; 21 22include "string.m"; 23 24# see login(6) 25login(id, password, dest: string): (string, ref Keyring->Authinfo) 26{ 27 sys = load Sys Sys->PATH; 28 kr = load Keyring Keyring->PATH; 29 if(kr == nil) 30 return nomod(Keyring->PATH); 31 32 ssl := load SSL SSL->PATH; 33 if(ssl == nil) 34 return nomod(SSL->PATH); 35 36 rand := load Random Random->PATH; 37 if(rand == nil) 38 return nomod(Random->PATH); 39 40 dial := load Dial Dial->PATH; 41 if(dial == nil) 42 return nomod(Dial->PATH); 43 44 if(dest == nil) 45 dest = "$SIGNER"; 46 dest = dial->netmkaddr(dest, "net", "inflogin"); 47 lc := dial->dial(dest, nil); 48 if(lc == nil) 49 return (sys->sprint("can't contact login service: %s: %r", dest), nil); 50 51 # push ssl, leave in clear mode for now 52 (err, c) := ssl->connect(lc.dfd); 53 if(c == nil) 54 return ("can't push ssl: " + err, nil); 55 lc.dfd = nil; 56 lc.cfd = nil; 57 58 # user->CA name 59 if(kr->putstring(c.dfd, id) < 0) 60 return (sys->sprint("can't send user name: %r"), nil); 61 62 # CA->user ACK 63 (s, why) := kr->getstring(c.dfd); 64 if(why != nil) 65 return ("remote: " + why, nil); 66 if(s != id) 67 return ("unexpected reply from signer: " + s, nil); 68 69 # user->CA ivec 70 ivec := rand->randombuf(rand->ReallyRandom, 8); 71 if(kr->putbytearray(c.dfd, ivec, len ivec) < 0) 72 return (sys->sprint("can't send initialization vector: %r"), nil); 73 74 # start encrypting 75 pwbuf := array of byte password; 76 digest := array[Keyring->SHA1dlen] of byte; 77 kr->sha1(pwbuf, len pwbuf, digest, nil); 78 pwbuf = array[8] of byte; 79 for(i := 0; i < 8; i++) 80 pwbuf[i] = digest[i] ^ digest[8+i]; 81 for(i = 0; i < 4; i++) 82 pwbuf[i] ^= digest[16+i]; 83 for(i = 0; i < 8; i++) 84 pwbuf[i] ^= ivec[i]; 85 err = ssl->secret(c, pwbuf, pwbuf); 86 if(err != nil) 87 return ("can't set secret: " + err, nil); 88 if(sys->fprint(c.cfd, "alg rc4") < 0) 89 return (sys->sprint("can't push alg rc4: %r"), nil); 90 #if(sys->fprint(c.cfd, "alg desebc") < 0) 91 # return (sys->sprint("can't push alg desecb: %r"), nil); 92 93 # CA -> user key(alpha**r0 mod p) 94 (s, err) = kr->getstring(c.dfd); 95 if(err != nil){ 96 if(err == "failure") # calculated secret is wrong 97 return ("name or secret incorrect (alpha**r0 mod p)", nil); 98 return ("remote:" + err, nil); 99 } 100 101 # stop encrypting 102 if(sys->fprint(c.cfd, "alg clear") < 0) 103 return (sys->sprint("can't push alg clear: %r"), nil); 104 alphar0 := IPint.b64toip(s); 105 106 # CA->user alpha 107 (s, err) = kr->getstring(c.dfd); 108 if(err != nil){ 109 if(err == "failure") 110 return ("name or secret incorrect (alpha)", nil); 111 return ("remote: " + err, nil); 112 } 113 info := ref Keyring->Authinfo; 114 info.alpha = IPint.b64toip(s); 115 116 # CA->user p 117 (s, err) = kr->getstring(c.dfd); 118 if(err != nil){ 119 if(err == "failure") 120 return ("name or secret incorrect (p)", nil); 121 return ("remote: " + err, nil); 122 } 123 info.p = IPint.b64toip(s); 124 125 # sanity check 126 bits := info.p.bits(); 127 abits := info.alpha.bits(); 128 if(abits > bits || abits < 2) 129 return ("bogus diffie hellman constants", nil); 130 131 # generate our random diffie hellman part 132 r1 := kr->IPint.random(bits/4, bits); 133 alphar1 := info.alpha.expmod(r1, info.p); 134 135 # user->CA alpha**r1 mod p 136 if(kr->putstring(c.dfd, alphar1.iptob64()) < 0) 137 return (sys->sprint("can't send (alpha**r1 mod p): %r"), nil); 138 139 # compute alpha**(r0*r1) mod p 140 alphar0r1 := alphar0.expmod(r1, info.p); 141 142 # turn on digesting 143 secret := alphar0r1.iptobytes(); 144 err = ssl->secret(c, secret, secret); 145 if(err != nil) 146 return ("can't set digesting: " + err, nil); 147 if(sys->fprint(c.cfd, "alg sha1") < 0) 148 return (sys->sprint("can't push alg sha1: %r"), nil); 149 150 # CA->user CA's public key, SHA(CA's public key + secret) 151 (s, err) = kr->getstring(c.dfd); 152 if(err != nil) 153 return ("can't get signer's public key: " + err, nil); 154 155 info.spk = kr->strtopk(s); 156 157 # generate a key pair 158 info.mysk = kr->genSKfromPK(info.spk, id); 159 info.mypk = kr->sktopk(info.mysk); 160 161 # user->CA user's public key, SHA(user's public key + secret) 162 if(kr->putstring(c.dfd, kr->pktostr(info.mypk)) < 0) 163 return (sys->sprint("can't send your public: %r"), nil); 164 165 # CA->user user's public key certificate 166 (s, err) = kr->getstring(c.dfd); 167 if(err != nil) 168 return ("can't get certificate: " + err, nil); 169 170 info.cert = kr->strtocert(s); 171 return(nil, info); 172} 173 174nomod(mod: string): (string, ref Keyring->Authinfo) 175{ 176 return (sys->sprint("can't load module %s: %r", mod), nil); 177} 178