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