xref: /inferno-os/appl/lib/auth.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1*37da2899SCharles.Forsyth# Inferno authentication protocol
2*37da2899SCharles.Forsythimplement Auth;
3*37da2899SCharles.Forsyth
4*37da2899SCharles.Forsythinclude "sys.m";
5*37da2899SCharles.Forsyth	sys: Sys;
6*37da2899SCharles.Forsyth
7*37da2899SCharles.Forsythinclude "keyring.m";
8*37da2899SCharles.Forsyth
9*37da2899SCharles.Forsythinclude "security.m";
10*37da2899SCharles.Forsyth	ssl: SSL;
11*37da2899SCharles.Forsyth
12*37da2899SCharles.Forsythinit(): string
13*37da2899SCharles.Forsyth{
14*37da2899SCharles.Forsyth	if(sys == nil)
15*37da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
16*37da2899SCharles.Forsyth	return nil;
17*37da2899SCharles.Forsyth}
18*37da2899SCharles.Forsyth
19*37da2899SCharles.Forsythserver(algs: list of string, ai: ref Keyring->Authinfo, fd: ref Sys->FD, setid: int): (ref Sys->FD, string)
20*37da2899SCharles.Forsyth{
21*37da2899SCharles.Forsyth	if(sys == nil)
22*37da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
23*37da2899SCharles.Forsyth	kr := load Keyring Keyring->PATH;
24*37da2899SCharles.Forsyth	if(kr == nil)
25*37da2899SCharles.Forsyth		return (nil, sys->sprint("%r"));
26*37da2899SCharles.Forsyth
27*37da2899SCharles.Forsyth	# mutual authentication
28*37da2899SCharles.Forsyth	(id_or_err, secret) := kr->auth(fd, ai, setid);
29*37da2899SCharles.Forsyth
30*37da2899SCharles.Forsyth	if(secret == nil){
31*37da2899SCharles.Forsyth		if(ai == nil && id_or_err == "no authentication information")
32*37da2899SCharles.Forsyth			id_or_err = "no server certificate";
33*37da2899SCharles.Forsyth		return (nil, id_or_err);
34*37da2899SCharles.Forsyth	}
35*37da2899SCharles.Forsyth	if(0)
36*37da2899SCharles.Forsyth		sys->fprint(sys->fildes(2), "secret is %s\n", dump(secret));
37*37da2899SCharles.Forsyth
38*37da2899SCharles.Forsyth	# have got a secret, get algorithm from client
39*37da2899SCharles.Forsyth	# check if the client algorithm is in the server algorithm list
40*37da2899SCharles.Forsyth	# client algorithm ::= ident (' ' ident)*
41*37da2899SCharles.Forsyth	# where ident is defined by ssl(3)
42*37da2899SCharles.Forsyth	algbuf := string kr->getmsg(fd);
43*37da2899SCharles.Forsyth	if(algbuf == nil)
44*37da2899SCharles.Forsyth		return (nil, sys->sprint("can't read client ssl algorithm: %r"));
45*37da2899SCharles.Forsyth	alg := "";
46*37da2899SCharles.Forsyth	(nil, calgs) := sys->tokenize(algbuf, " /");
47*37da2899SCharles.Forsyth	for(; calgs != nil; calgs = tl calgs){
48*37da2899SCharles.Forsyth		calg := hd calgs;
49*37da2899SCharles.Forsyth		if(algs != nil){	# otherwise we suck it and see
50*37da2899SCharles.Forsyth			for(sl := algs; sl != nil; sl = tl sl)
51*37da2899SCharles.Forsyth				if(hd sl == calg)
52*37da2899SCharles.Forsyth					break;
53*37da2899SCharles.Forsyth			if(sl == nil)
54*37da2899SCharles.Forsyth				return (nil, "unsupported client algorithm: " + calg);
55*37da2899SCharles.Forsyth		}
56*37da2899SCharles.Forsyth		alg += calg + " ";
57*37da2899SCharles.Forsyth	}
58*37da2899SCharles.Forsyth	if(alg != nil)
59*37da2899SCharles.Forsyth		alg = alg[0:len alg - 1];
60*37da2899SCharles.Forsyth
61*37da2899SCharles.Forsyth	# don't push ssl if server supports nossl
62*37da2899SCharles.Forsyth	if(alg == nil || alg == "none")
63*37da2899SCharles.Forsyth		return (fd, id_or_err);
64*37da2899SCharles.Forsyth
65*37da2899SCharles.Forsyth	# push ssl and turn on algorithms
66*37da2899SCharles.Forsyth	ssl = load SSL SSL->PATH;
67*37da2899SCharles.Forsyth	if(ssl == nil)
68*37da2899SCharles.Forsyth		return (nil, sys->sprint("can't load ssl: %r"));
69*37da2899SCharles.Forsyth	(c, err) := pushssl(fd, secret, secret, alg);
70*37da2899SCharles.Forsyth	if(c == nil)
71*37da2899SCharles.Forsyth		return (nil, "push ssl: " + err);
72*37da2899SCharles.Forsyth	return (c, id_or_err);
73*37da2899SCharles.Forsyth}
74*37da2899SCharles.Forsyth
75*37da2899SCharles.Forsythclient(alg: string, ai: ref Keyring->Authinfo, fd: ref Sys->FD): (ref Sys->FD, string)
76*37da2899SCharles.Forsyth{
77*37da2899SCharles.Forsyth	if(sys == nil)
78*37da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
79*37da2899SCharles.Forsyth	kr := load Keyring Keyring->PATH;
80*37da2899SCharles.Forsyth	if(kr == nil)
81*37da2899SCharles.Forsyth		return (nil, sys->sprint("%r"));
82*37da2899SCharles.Forsyth
83*37da2899SCharles.Forsyth	if(alg == nil)
84*37da2899SCharles.Forsyth		alg = "none";
85*37da2899SCharles.Forsyth
86*37da2899SCharles.Forsyth	# mutual authentication
87*37da2899SCharles.Forsyth	(id_or_err, secret) := kr->auth(fd, ai, 0);
88*37da2899SCharles.Forsyth	if(secret == nil)
89*37da2899SCharles.Forsyth		return (nil, id_or_err);
90*37da2899SCharles.Forsyth
91*37da2899SCharles.Forsyth	# send algorithm
92*37da2899SCharles.Forsyth	buf := array of byte alg;
93*37da2899SCharles.Forsyth	if(kr->sendmsg(fd, buf, len buf) < 0)
94*37da2899SCharles.Forsyth		return (nil, sys->sprint("can't send ssl algorithm: %r"));
95*37da2899SCharles.Forsyth
96*37da2899SCharles.Forsyth	# don't push ssl if server supports no ssl connection
97*37da2899SCharles.Forsyth	if(alg == "none")
98*37da2899SCharles.Forsyth		return (fd, id_or_err);
99*37da2899SCharles.Forsyth
100*37da2899SCharles.Forsyth	# push ssl and turn on algorithm
101*37da2899SCharles.Forsyth	ssl = load SSL SSL->PATH;
102*37da2899SCharles.Forsyth	if(ssl == nil)
103*37da2899SCharles.Forsyth		return (nil, sys->sprint("can't load ssl: %r"));
104*37da2899SCharles.Forsyth	(c, err) := pushssl(fd, secret, secret, alg);
105*37da2899SCharles.Forsyth	if(c == nil)
106*37da2899SCharles.Forsyth		return (nil, "push ssl: " + err);
107*37da2899SCharles.Forsyth	return (c, id_or_err);
108*37da2899SCharles.Forsyth}
109*37da2899SCharles.Forsyth
110*37da2899SCharles.Forsythauth(ai: ref Keyring->Authinfo, keyspec: string, alg: string, fd: ref Sys->FD): (ref Sys->FD, ref Keyring->Authinfo, string)
111*37da2899SCharles.Forsyth{
112*37da2899SCharles.Forsyth	if(sys == nil)
113*37da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
114*37da2899SCharles.Forsyth	kr := load Keyring Keyring->PATH;
115*37da2899SCharles.Forsyth	if(kr == nil)
116*37da2899SCharles.Forsyth		return (nil, nil, sys->sprint("can't load %s: %r", Keyring->PATH));
117*37da2899SCharles.Forsyth	if(alg == nil)
118*37da2899SCharles.Forsyth		alg = "none";
119*37da2899SCharles.Forsyth	if(ai == nil && keyspec != nil){
120*37da2899SCharles.Forsyth		ai = key(keyspec);
121*37da2899SCharles.Forsyth		if(ai == nil)
122*37da2899SCharles.Forsyth			return (nil, nil, sys->sprint("can't obtain key: %r"));
123*37da2899SCharles.Forsyth	}
124*37da2899SCharles.Forsyth
125*37da2899SCharles.Forsyth	# mutual authentication
126*37da2899SCharles.Forsyth	(id_or_err, secret) := kr->auth(fd, ai, 0);
127*37da2899SCharles.Forsyth	if(secret == nil)
128*37da2899SCharles.Forsyth		return (nil, nil, id_or_err);
129*37da2899SCharles.Forsyth
130*37da2899SCharles.Forsyth	# send algorithm
131*37da2899SCharles.Forsyth	buf := array of byte alg;
132*37da2899SCharles.Forsyth	if(kr->sendmsg(fd, buf, len buf) < 0)
133*37da2899SCharles.Forsyth		return (nil, nil, sys->sprint("can't send ssl algorithm: %r"));
134*37da2899SCharles.Forsyth
135*37da2899SCharles.Forsyth	if(0){		# TO DO
136*37da2899SCharles.Forsyth		hisalg := string kr->getmsg(fd);
137*37da2899SCharles.Forsyth		if(hisalg == nil)
138*37da2899SCharles.Forsyth			return (nil, nil, sys->sprint("can't get remote algorithm: %r"));
139*37da2899SCharles.Forsyth		# TO DO: compare the two, sort it out if they aren't equal
140*37da2899SCharles.Forsyth	}
141*37da2899SCharles.Forsyth
142*37da2899SCharles.Forsyth	# don't push ssl if server supports no ssl connection
143*37da2899SCharles.Forsyth	if(alg == "none")
144*37da2899SCharles.Forsyth		return (fd, nil, id_or_err);
145*37da2899SCharles.Forsyth
146*37da2899SCharles.Forsyth	# push ssl and turn on algorithm
147*37da2899SCharles.Forsyth	ssl = load SSL SSL->PATH;
148*37da2899SCharles.Forsyth	if(ssl == nil)
149*37da2899SCharles.Forsyth		return (nil, nil, sys->sprint("can't load ssl: %r"));
150*37da2899SCharles.Forsyth	(c, err) := pushssl(fd, secret, secret, alg);
151*37da2899SCharles.Forsyth	if(c == nil)
152*37da2899SCharles.Forsyth		return (nil, nil, "push ssl: " + err);
153*37da2899SCharles.Forsyth	return (c, nil, id_or_err);
154*37da2899SCharles.Forsyth}
155*37da2899SCharles.Forsyth
156*37da2899SCharles.Forsythdump(b: array of byte): string
157*37da2899SCharles.Forsyth{
158*37da2899SCharles.Forsyth	s := "";
159*37da2899SCharles.Forsyth	for(i := 0; i < len b; i++)
160*37da2899SCharles.Forsyth		s += sys->sprint("%.2ux", int b[i]);
161*37da2899SCharles.Forsyth	return s;
162*37da2899SCharles.Forsyth}
163*37da2899SCharles.Forsyth
164*37da2899SCharles.Forsyth# push an SSLv2 Record Layer onto the fd
165*37da2899SCharles.Forsythpushssl(fd: ref Sys->FD, secretin, secretout: array of byte, alg: string): (ref Sys->FD, string)
166*37da2899SCharles.Forsyth{
167*37da2899SCharles.Forsyth	(err, c) := ssl->connect(fd);
168*37da2899SCharles.Forsyth	if(err != nil)
169*37da2899SCharles.Forsyth		return (nil, "can't connect ssl: " + err);
170*37da2899SCharles.Forsyth
171*37da2899SCharles.Forsyth	err = ssl->secret(c, secretin, secretout);
172*37da2899SCharles.Forsyth	if(err != nil)
173*37da2899SCharles.Forsyth		return (nil, "can't write secret: " + err);
174*37da2899SCharles.Forsyth
175*37da2899SCharles.Forsyth	if(sys->fprint(c.cfd, "alg %s", alg) < 0)
176*37da2899SCharles.Forsyth		return (nil, sys->sprint("can't push algorithm %s: %r", alg));
177*37da2899SCharles.Forsyth
178*37da2899SCharles.Forsyth	return (c.dfd, nil);
179*37da2899SCharles.Forsyth}
180*37da2899SCharles.Forsyth
181*37da2899SCharles.Forsythkey(keyspec: string): ref Keyring->Authinfo
182*37da2899SCharles.Forsyth{
183*37da2899SCharles.Forsyth	f := keyfile(keyspec);
184*37da2899SCharles.Forsyth	if(f == nil)
185*37da2899SCharles.Forsyth		return nil;
186*37da2899SCharles.Forsyth	kr := load Keyring Keyring->PATH;
187*37da2899SCharles.Forsyth	if(kr == nil){
188*37da2899SCharles.Forsyth		sys->werrstr(sys->sprint("can't load %s: %r", Keyring->PATH));
189*37da2899SCharles.Forsyth		return nil;
190*37da2899SCharles.Forsyth	}
191*37da2899SCharles.Forsyth	return kr->readauthinfo(f);
192*37da2899SCharles.Forsyth}
193*37da2899SCharles.Forsyth
194*37da2899SCharles.Forsyth#
195*37da2899SCharles.Forsyth# look for key in old style keyring directory;
196*37da2899SCharles.Forsyth# closest match to [net!]addr[!svc]
197*37da2899SCharles.Forsyth#
198*37da2899SCharles.Forsyth
199*37da2899SCharles.Forsythkeyfile(keyspec: string): string
200*37da2899SCharles.Forsyth{
201*37da2899SCharles.Forsyth	if(sys == nil)
202*37da2899SCharles.Forsyth		sys = load Sys Sys->PATH;
203*37da2899SCharles.Forsyth	al := parseattr(keyspec);
204*37da2899SCharles.Forsyth	keyname := get(al, "key");
205*37da2899SCharles.Forsyth	if(keyname != nil){
206*37da2899SCharles.Forsyth		# explicit keyname overrides rest of spec
207*37da2899SCharles.Forsyth		if(keyname[0] == '/' ||
208*37da2899SCharles.Forsyth		   len keyname > 2 && keyname[0:2]=="./" ||
209*37da2899SCharles.Forsyth		   len keyname > 3 && keyname[0:3]=="../")
210*37da2899SCharles.Forsyth			return keyname;	# don't add directory
211*37da2899SCharles.Forsyth		return keydir()+keyname;
212*37da2899SCharles.Forsyth	}
213*37da2899SCharles.Forsyth	net := "net";
214*37da2899SCharles.Forsyth	svc := get(al, "service");
215*37da2899SCharles.Forsyth	addr := get(al, "server");
216*37da2899SCharles.Forsyth	(nf, flds) := sys->tokenize(addr, "!");	# compatibility
217*37da2899SCharles.Forsyth	if(nf > 1){
218*37da2899SCharles.Forsyth		net = hd flds;
219*37da2899SCharles.Forsyth		addr = hd tl flds;
220*37da2899SCharles.Forsyth	}
221*37da2899SCharles.Forsyth	if(addr != nil)
222*37da2899SCharles.Forsyth		keyname = addr;
223*37da2899SCharles.Forsyth	else
224*37da2899SCharles.Forsyth		keyname = "default";
225*37da2899SCharles.Forsyth	kd := keydir();
226*37da2899SCharles.Forsyth	dom := get(al, "dom");
227*37da2899SCharles.Forsyth	if(dom != nil){
228*37da2899SCharles.Forsyth		if((cert := exists(kd+dom)) != nil)
229*37da2899SCharles.Forsyth			return cert;
230*37da2899SCharles.Forsyth	}
231*37da2899SCharles.Forsyth	if(keyname == "default")
232*37da2899SCharles.Forsyth		return kd+"default";
233*37da2899SCharles.Forsyth	if(net == "net")
234*37da2899SCharles.Forsyth		l := "net!" :: "tcp!" :: nil;
235*37da2899SCharles.Forsyth	else
236*37da2899SCharles.Forsyth		l = net+"!" :: nil;
237*37da2899SCharles.Forsyth	if(svc != nil){
238*37da2899SCharles.Forsyth		for(nl := l; nl != nil; nl = tl nl){
239*37da2899SCharles.Forsyth			cert := exists(kd+(hd nl)+keyname+"!"+svc);	# most specific
240*37da2899SCharles.Forsyth			if(cert != nil)
241*37da2899SCharles.Forsyth				return cert;
242*37da2899SCharles.Forsyth		}
243*37da2899SCharles.Forsyth	}
244*37da2899SCharles.Forsyth	for(nl := l; nl != nil; nl = tl nl){
245*37da2899SCharles.Forsyth		cert := exists(kd+(hd nl)+keyname);
246*37da2899SCharles.Forsyth		if(cert != nil)
247*37da2899SCharles.Forsyth			return cert;
248*37da2899SCharles.Forsyth	}
249*37da2899SCharles.Forsyth	cert := exists(kd+keyname);	# unadorned
250*37da2899SCharles.Forsyth	if(cert != nil)
251*37da2899SCharles.Forsyth		return cert;
252*37da2899SCharles.Forsyth	if(keyname != "default"){
253*37da2899SCharles.Forsyth		cert = exists(kd+"default");
254*37da2899SCharles.Forsyth		if(cert != nil)
255*37da2899SCharles.Forsyth			return cert;
256*37da2899SCharles.Forsyth	}
257*37da2899SCharles.Forsyth	return kd+keyname;
258*37da2899SCharles.Forsyth}
259*37da2899SCharles.Forsyth
260*37da2899SCharles.Forsythkeydir(): string
261*37da2899SCharles.Forsyth{
262*37da2899SCharles.Forsyth	fd := sys->open("/dev/user", Sys->OREAD);
263*37da2899SCharles.Forsyth	if(fd == nil)
264*37da2899SCharles.Forsyth		return nil;
265*37da2899SCharles.Forsyth	b := array[Sys->NAMEMAX] of byte;
266*37da2899SCharles.Forsyth	nr := sys->read(fd, b, len b);
267*37da2899SCharles.Forsyth	if(nr <= 0){
268*37da2899SCharles.Forsyth		sys->werrstr("can't read /dev/user");
269*37da2899SCharles.Forsyth		return nil;
270*37da2899SCharles.Forsyth	}
271*37da2899SCharles.Forsyth	user := string b[0:nr];
272*37da2899SCharles.Forsyth	return "/usr/" + user + "/keyring/";
273*37da2899SCharles.Forsyth}
274*37da2899SCharles.Forsyth
275*37da2899SCharles.Forsythexists(f: string): string
276*37da2899SCharles.Forsyth{
277*37da2899SCharles.Forsyth	(ok, nil) := sys->stat(f);
278*37da2899SCharles.Forsyth	if(0)sys->fprint(sys->fildes(2), "exists: %q %d\n", f, ok>=0);
279*37da2899SCharles.Forsyth	if(ok >= 0)
280*37da2899SCharles.Forsyth		return f;
281*37da2899SCharles.Forsyth	return nil;
282*37da2899SCharles.Forsyth}
283*37da2899SCharles.Forsyth
284*37da2899SCharles.ForsythAattr, Aval, Aquery: con iota;
285*37da2899SCharles.Forsyth
286*37da2899SCharles.ForsythAttr: adt {
287*37da2899SCharles.Forsyth	tag:	int;
288*37da2899SCharles.Forsyth	name:	string;
289*37da2899SCharles.Forsyth	val:	string;
290*37da2899SCharles.Forsyth};
291*37da2899SCharles.Forsyth
292*37da2899SCharles.Forsythparseattr(s: string): list of ref Attr
293*37da2899SCharles.Forsyth{
294*37da2899SCharles.Forsyth	(nil, fld) := sys->tokenize(s, " \t\n");	# should do quoting; later
295*37da2899SCharles.Forsyth	rfld := fld;
296*37da2899SCharles.Forsyth	for(fld = nil; rfld != nil; rfld = tl rfld)
297*37da2899SCharles.Forsyth		fld = (hd rfld) :: fld;
298*37da2899SCharles.Forsyth	attrs: list of ref Attr;
299*37da2899SCharles.Forsyth	for(; fld != nil; fld = tl fld){
300*37da2899SCharles.Forsyth		n := hd fld;
301*37da2899SCharles.Forsyth		a := "";
302*37da2899SCharles.Forsyth		tag := Aattr;
303*37da2899SCharles.Forsyth		for(i:=0; i<len n; i++)
304*37da2899SCharles.Forsyth			if(n[i] == '='){
305*37da2899SCharles.Forsyth				a = n[i+1:];
306*37da2899SCharles.Forsyth				n = n[0:i];
307*37da2899SCharles.Forsyth				tag = Aval;
308*37da2899SCharles.Forsyth			}
309*37da2899SCharles.Forsyth		if(len n == 0)
310*37da2899SCharles.Forsyth			continue;
311*37da2899SCharles.Forsyth		if(tag == Aattr && len n > 1 && n[len n-1] == '?'){
312*37da2899SCharles.Forsyth			tag = Aquery;
313*37da2899SCharles.Forsyth			n = n[0:len n-1];
314*37da2899SCharles.Forsyth		}
315*37da2899SCharles.Forsyth		attrs = ref Attr(tag, n, a) :: attrs;
316*37da2899SCharles.Forsyth	}
317*37da2899SCharles.Forsyth	return attrs;
318*37da2899SCharles.Forsyth}
319*37da2899SCharles.Forsyth
320*37da2899SCharles.Forsythget(al: list of ref Attr, n: string): string
321*37da2899SCharles.Forsyth{
322*37da2899SCharles.Forsyth	for(; al != nil; al = tl al)
323*37da2899SCharles.Forsyth		if((a := hd al).name == n && a.tag == Aval)
324*37da2899SCharles.Forsyth			return a.val;
325*37da2899SCharles.Forsyth	return nil;
326*37da2899SCharles.Forsyth}
327