implement Oldauth; # # TO DO # - more error checking? # - details of auth error handling # include "sys.m"; sys: Sys; include "ipints.m"; ipints: IPints; IPint: import ipints; include "crypt.m"; crypt: Crypt; PK, SK, PKsig: import crypt; include "msgio.m"; msgio: Msgio; include "oldauth.m"; init() { sys = load Sys Sys->PATH; ipints = load IPints IPints->PATH; crypt = load Crypt Crypt->PATH; msgio = load Msgio Msgio->PATH; msgio->init(); } efmt() { sys->werrstr("input or format error"); } readauthinfo(filename: string): ref Authinfo { fd := sys->open(filename, Sys->OREAD); if(fd == nil) return nil; a := array[5] of string; for(i := 0; i < len a; i++){ (s, err) := getstr(fd); if(err != nil){ sys->werrstr(sys->sprint("%q: input or format error", filename)); return nil; } a[i] = s; } info := ref Authinfo; (info.spk, nil) = strtopk(a[0]); info.cert = strtocert(a[1]); (info.mysk, info.owner) = strtosk(a[2]); if(info.spk == nil || info.cert == nil || info.mysk == nil){ efmt(); return nil; } info.mypk = crypt->sktopk(info.mysk); info.alpha = IPint.strtoip(a[3], 64); info.p = IPint.strtoip(a[4], 64); if(info.alpha == nil || info.p == nil){ efmt(); return nil; } return info; } writeauthinfo(filename: string, info: ref Authinfo): int { if(info.alpha == nil || info.p == nil || info.spk == nil || info.mysk == nil || info.cert == nil){ sys->werrstr("invalid authinfo"); return -1; } a := array[5] of string; a[0] = pktostr(info.spk, info.cert.signer); # signer's public key a[1] = certtostr(info.cert); # certificate for my public key a[2] = sktostr(info.mysk, info.owner); # my secret/public key a[3] = b64(info.alpha); # diffie hellman base a[4] = b64(info.p); # diffie hellman modulus fd := sys->open(filename, Sys->OWRITE|Sys->OTRUNC); if(fd == nil){ fd = sys->create(filename, Sys->OWRITE, 8r600); if(fd == nil){ fd = sys->open(filename, Sys->OWRITE); if(fd == nil) return -1; } } for(i := 0; i < len a; i++) if(sendstr(fd, a[i]) <= 0) return -1; return 0; } sendstr(fd: ref Sys->FD, s: string): int { a := array of byte s; return msgio->sendmsg(fd, a, len a); } getstr(fd: ref Sys->FD): (string, string) { b := msgio->getmsg(fd); if(b == nil) return (nil, sys->sprint("%r")); return (string b, nil); } certtostr(c: ref Certificate): string { s := sys->sprint("%s\n%s\n%s\n%ud\n", c.sa, c.ha, c.signer, c.exp); pick r := c.sig { RSA => s += b64(r.n)+"\n"; Elgamal => s += b64(r.r)+"\n"+b64(r.s)+"\n"; DSA => s += b64(r.r)+"\n"+b64(r.s)+"\n"; * => raise "unknown key type"; } return s; } pktostr(pk: ref PK, owner: string): string { pick k := pk { RSA => s := sys->sprint("rsa\n%s\n", owner); s += b64(k.n)+"\n"+b64(k.ek)+"\n"; return s; Elgamal => s := sys->sprint("elgamal\n%s\n", owner); s += b64(k.p)+"\n"+b64(k.alpha)+"\n"+b64(k.key)+"\n"; return s; DSA => s := sys->sprint("dsa\n%s\n", owner); s += b64(k.p)+"\n"+b64(k.q)+"\n"+b64(k.alpha)+"\n"+b64(k.key)+"\n"; return s; * => raise "unknown key type"; } } sktostr(sk: ref SK, owner: string): string { pick k := sk { RSA => s := sys->sprint("rsa\n%s\n", owner); s += b64(k.pk.n)+"\n"+b64(k.pk.ek)+"\n"+b64(k.dk)+"\n"+ b64(k.p)+"\n"+b64(k.q)+"\n"+ b64(k.kp)+"\n"+b64(k.kq)+"\n"+ k.c2.iptob64()+"\n"; return s; Elgamal => pk := k.pk; s := sys->sprint("elgamal\n%s\n", owner); s += b64(pk.p)+"\n"+b64(pk.alpha)+"\n"+b64(pk.key)+"\n"+b64(k.secret)+"\n"; return s; DSA => pk := k.pk; s := sys->sprint("dsa\n%s\n", owner); s += b64(pk.p)+"\n"+b64(pk.q)+"\n"+b64(pk.alpha)+"\n"+b64(k.secret)+"\n"; return s; * => raise "unknown key type"; } } fields(s: string): array of string { (nf, flds) := sys->tokenize(s, "\n^"); a := array[nf] of string; for(i := 0; i < len a; i++){ a[i] = hd flds; flds = tl flds; } return a; } bigs(a: array of string): array of ref IPint { b := array[len a] of ref IPint; for(i := 0; i < len b; i++){ b[i] = IPint.strtoip(a[i], 64); if(b[i] == nil) return nil; } return b; } need[T](a: array of T, min: int): int { if(len a < min){ efmt(); return 1; } return 0; } strtocert(s: string): ref Certificate { f := fields(s); if(need(f, 4)) return nil; sa := f[0]; ha := f[1]; signer := f[2]; exp := int big f[3]; # unsigned b := bigs(f[4:]); case f[0] { "rsa" => if(need(b, 1)) return nil; return ref Certificate(sa, ha, signer, exp, ref PKsig.RSA(b[0])); "elgamal" => if(need(b, 2)) return nil; return ref Certificate(sa, ha, signer, exp, ref PKsig.Elgamal(b[0], b[1])); "dsa" => if(need(b, 2)) return nil; return ref Certificate(sa, ha, signer, exp, ref PKsig.DSA(b[0], b[1])); * => sys->werrstr("unknown algorithm: "+f[0]); return nil; } } strtopk(s: string): (ref PK, string) { f := fields(s); if(need(f, 3)) return (nil, "format error"); sa := f[0]; owner := f[1]; b := bigs(f[2:]); case sa { "rsa" => if(need(b, 2)) return (nil, "format error"); return (ref PK.RSA(b[0], b[1]), owner); "elgamal" => if(need(b, 3)) return (nil, "format error"); return (ref PK.Elgamal(b[0], b[1], b[2]), owner); "dsa" => if(need(b, 4)) return (nil, "format error"); return (ref PK.DSA(b[0], b[1], b[2], b[3]), owner); * => return (nil, "unknown algorithm: "+f[0]); } } strtosk(s: string): (ref SK, string) { f := fields(s); if(need(f, 3)) return (nil, "format error"); sa := f[0]; owner := f[1]; b := bigs(f[2:]); case sa { "rsa" => if(need(b, 8)) return (nil, "format error"); return (ref SK.RSA(ref PK.RSA(b[0], b[1]), b[2], b[3], b[4], b[5], b[6], b[7]), owner); "elgamal" => if(need(b, 4)) return (nil, "format error"); return (ref SK.Elgamal(ref PK.Elgamal(b[0], b[1], b[2]), b[3]), owner); "dsa" => if(need(b, 5)) return (nil, "format error"); return (ref SK.DSA(ref PK.DSA(b[0], b[1], b[2], b[3]), b[4]), owner); * => return (nil, "unknown algorithm: "+f[0]); } } skalg(sk: ref SK): string { if(sk == nil) return "nil"; case tagof sk { tagof SK.RSA => return "rsa"; tagof SK.Elgamal => return "elgamal"; tagof SK.DSA => return "dsa"; * => return "gok"; } } sign(sk: ref SK, signer: string, exp: int, state: ref Crypt->DigestState, ha: string): ref Certificate { # add signer name and expiration time to hash if(state == nil) return nil; a := sys->aprint("%s %d", signer, exp); digest := hash(ha, a, state); if(digest == nil) return nil; b := IPint.bebytestoip(digest); return ref Certificate(skalg(sk), ha, signer, exp, crypt->sign(sk, b)); } verify(pk: ref PK, cert: ref Certificate, state: ref Crypt->DigestState): int { if(state == nil) return 0; a := sys->aprint("%s %d", cert.signer, cert.exp); digest := hash(cert.ha, a, state); if(digest == nil) return 0; b := IPint.bebytestoip(digest); return crypt->verify(pk, cert.sig, b); } hash(ha: string, a: array of byte, state: ref Crypt->DigestState): array of byte { digest: array of byte; case ha { "sha" or "sha1" => digest = array[Crypt->SHA1dlen] of byte; crypt->sha1(a, len a, digest, state); "md5" => digest = array[Crypt->MD5dlen] of byte; crypt->md5(a, len a, digest, state); * => # don't bother with md4 sys->werrstr("unimplemented algorithm: "+ha); return nil; } return digest; } b64(ip: ref IPint): string { return ip.iptob64z(); }