xref: /inferno-os/appl/lib/login.b (revision ddf161d27871e47d85fd56e8403c715af8ce43c8)
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