ref: babf901b4a508c3ec5d1f89655f10377bbdf9637
dir: /appl/lib/oldauth.b/
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();
}