diff options
| author | forsyth <forsyth@vitanuova.com> | 2011-01-04 10:45:26 +0000 |
|---|---|---|
| committer | forsyth <forsyth@vitanuova.com> | 2011-01-04 10:45:26 +0000 |
| commit | 25b96b1d6a760df53b31e14ed1ae5f3c36e87bf5 (patch) | |
| tree | a1a1b0a5954a496ce32a837d97c2a7d9ad695935 | |
| parent | f82345d78fe94509235747eb0ac46275d2afe5a7 (diff) | |
20110104-1044
| -rw-r--r-- | appl/lib/mkfile | 2 | ||||
| -rw-r--r-- | appl/lib/oldauth.b | 344 | ||||
| -rw-r--r-- | dis/lib/oldauth.dis | bin | 0 -> 6456 bytes | |||
| -rw-r--r-- | man/2/security-oldauth | 246 | ||||
| -rw-r--r-- | module/oldauth.m | 48 |
5 files changed, 640 insertions, 0 deletions
diff --git a/appl/lib/mkfile b/appl/lib/mkfile index e681967e..279ca1ac 100644 --- a/appl/lib/mkfile +++ b/appl/lib/mkfile @@ -77,6 +77,8 @@ TARG=\ nametree.dis\ names.dis\ newns.dis\ + ninep.dis\ + oldauth.dis\ palm.dis\ palmdb.dis\ palmfile.dis\ diff --git a/appl/lib/oldauth.b b/appl/lib/oldauth.b new file mode 100644 index 00000000..60bd9f54 --- /dev/null +++ b/appl/lib/oldauth.b @@ -0,0 +1,344 @@ +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(); +} diff --git a/dis/lib/oldauth.dis b/dis/lib/oldauth.dis Binary files differnew file mode 100644 index 00000000..10481a49 --- /dev/null +++ b/dis/lib/oldauth.dis diff --git a/man/2/security-oldauth b/man/2/security-oldauth new file mode 100644 index 00000000..e6d48e40 --- /dev/null +++ b/man/2/security-oldauth @@ -0,0 +1,246 @@ +.TH SECURITY-OLDAUTH 2 +.SH NAME +oldauth: certtostr, pktostr, sktostr, strtocert, strtopk, strtosk, sign, verify, readauthinfo, writeauthinfo \- encoding for original Inferno authentication protocol +.SH SYNOPSIS +.EX +include "ipints.m"; +include "crypt.m"; +include "oldauth.m"; +oldauth := load Oldauth Oldauth->PATH; + +Certificate: adt +{ + sa: string; + ha: string; + signer: string; + exp: int; + sig: ref Crypt->PKsig; +}; + +Authinfo: adt +{ + mysk: ref Crypt->SK; + mypk: ref Crypt->PK; + owner: string; + cert: ref Certificate; + spk: ref Crypt->PK; + alpha: ref IPints->IPint; + p: ref IPints->IPint; +}; + +sign: fn (sk: ref Crypt->SK, signer: string, exp: int, + state: ref Crypt->DigestState, ha: string): ref Certificate; +verify: fn (pk: ref Crypt->PK, cert: ref Certificate, + state: ref Crypt->DigestState): int; + +strtocert: fn(s: string): ref Certificate; +certtostr: fn(c: ref Certificate): string; +strtopk: fn(s: string): (ref Crypt->PK, string); +pktostr: fn(pk: ref Crypt->PK, owner: string): string; +strtosk: fn(s: string): (ref Crypt->SK, string); +sktostr: fn(sk: ref Crypt->SK, owner: string): string; + +readauthinfo: fn(filename: string): ref Authinfo; +writeauthinfo: fn(filename: string, info: ref Authinfo): int; +.EE +.SH DESCRIPTION +Certificates, public keys, and private keys are passed over networks and between applications using a Unicode representation. +This collection of functions provide a means to convert adts supplied by the system to and from their portable textual representation. These routines are used by +.IR login (2) +and +.IR factotum (4) +to implement the Inferno authentication protocol. +.PP +Public and private keys are represented by +.B Crypt->PK +and +.B Crypt->SK +(see +.IR keyring-intro (2)). +An authentication domain is represented by +the public key of the domain's +.IR signer , +typically in control of a +.IR keyfs (4) +and running a +.IR logind (8). +Two adts associate a public/private key pair with a user name within a specific authentication domain: +.TP +.B Authinfo +The +.B Authinfo +adt contains an individual user's private and public key, a human-readable name for the key (eg, a user name), +the signer's certificate +and the signer's public key, and the Diffie-Hellman parameters. +The signer's certificate binds the user's public key to the given key name in the signer's domain. +.TP +.B Certificate +The +.B Certificate +adt contains a digital signature with the certification of the trusted authority (CA). +The signature covers not only the user's public key, but the key's name, the signer's name and +the expiration time of the certificate. +Both the key's name and the signer's name are local to the signer's domain. +.PP +.B Init +must be called before using any other operation in the module. +.PP +.B Sign +returns a Certificate containing the digital signature using secret key +.I sk +of a digest's +.IR state , +which is the output of the hash algorithm named +.IR ha , +combined with the hash of the signer's name, and the certificate's expiration time (in seconds from the Epoch). +Valid hash algorithms are +.B sha1 +and +.BR md5 . +The expiry time should be zero if the certificate does not expire. +Typically the +.I state +is the result of hashing +.IP +.EX +array of byte pktostr(pk, username) +.EE +.PP +for a given public key +.I pk +that is associated with the given +.I username +by the signer. +.PP +.B Verify +checks that the given Certificate is the result of signing the given +.I state +using the secret (private) key corresponding to public key +.IR pk . +It returns true (non-zero) if the certificate is valid, including the signer's name, and the expiration time; +the caller must enforce the expiration time if desired. +It returns false (zero) if the certificate is invalid. +. ####### +.PP +.B Sign +creates a digital signature of a digest from the concatenation of: a message, the name of the signer, and an expiration time. +.I State +is the digest state after running +.BR sha1 , +.B md4 +or +.B md5 +over the message. +.I Ha +is a string specifying the hash algorithm to use: +.B +"sha"\fR, +.B +"sha1"\fR, +.B +"md4"\fR +or +.B +"md5"\fR. +.B Sign +extends the digest to cover the signer's name +(taken from the private key, +.IR sk ) +and the expiration time. +It returns a certificate containing the digital signature of the digest, signer name, hash algorithm and signature algorithm. +If any parameter is invalid, +.B sign +returns nil. +The signature algorithm is implied by the type of the private key. +.PP +.B Verify +uses public key +.I pk +to verify a certificate. +It returns non-zero (true) if the certificate is valid; zero (false) otherwise. +.I State +is the digest state after running the chosen digest algorithm +over the message. +. ####### +.PP +The remaining operations fetch and store those values and convert to and from text representations for use in protocols and for storage. +.PP +.B Strtocert +takes a string argument containing a varying number of newline-separated fields: +a signature algorithm, a hash algorithm, a signer's name, an expiration time, and values representing a digital signature. +It returns the corresponding +.BR Certificate . +If the string is of improper format, the result is +.IR nil . +.PP +.B Certtostr +performs the inverse operation: takes the +.B Certificate +.I c +and produces a text string suitable for communication over a network. +Note that the string will contain newline characters. +.PP +.B Strtopk +and +.B strtosk +take as their arguments a string +.I s +representing the public and private keys respectively. +.I S +contains an algorithm name, a user name and values representing the key. +Each returns a tuple +.BI ( k,\ s ), +where +.I k +is the resulting key value (ie, +.B Crypt->PK +or +.BR Crypt->SK ) +and +.I s +is a string giving the name associated with the key, typically a user name. +If the format of +.I s +is invalid, +.I k +is +.IR nil , +and +.I s +contains a diagnostic. +.PP +.B Pktostr +and +.B sktostr +perform the inverse operations: +they take a public key (secret key) +.I pk +or +.IR sk , +the +.I owner +name to be associated with that key, and produce a printable representation as a string. +The +.I owner +names the user that owns the key; in the case of a public key, +the user is expected to possess the corresponding private key. +.PP +.B Readauthinfo +reads a representation of an +.B Authinfo +from a file. +It returns nil if there is a read error or a conversion error; +it returns a reference to the +.B Authinfo +otherwise. +.PP +.B Writeauthinfo +writes a representation of +.I info +to a file. It returns -1 if the write operation fails, 0 otherwise. +.SH SOURCE +.B /appl/lib/oldauth.b +.SH SEE ALSO +.IR crypt-intro (2), +.IR ipints (2), +.IR security-intro (2) diff --git a/module/oldauth.m b/module/oldauth.m new file mode 100644 index 00000000..df1e6890 --- /dev/null +++ b/module/oldauth.m @@ -0,0 +1,48 @@ +Oldauth: module +{ + PATH: con "/dis/lib/oldauth.dis"; + + init: fn(); + + # Inferno certificate + Certificate: adt + { + sa: string; # signature algorithm + ha: string; # hash algorithm + signer: string; # name of signer + exp: int; # expiration date + sig: ref Crypt->PKsig; + }; + + # authentication info + Authinfo: adt + { + mysk: ref Crypt->SK; # my private key + mypk: ref Crypt->PK; # my public key + owner: string; # owner of mypk for certificate + cert: ref Certificate; # signature of my public key + spk: ref Crypt->PK; # signers public key + alpha: ref IPints->IPint; # diffie helman parameters + p: ref IPints->IPint; + }; + + # auth io + readauthinfo: fn(filename: string): ref Authinfo; + writeauthinfo: fn(filename: string, info: ref Authinfo): int; + + # convert types to text in a canonical form + certtostr: fn (c: ref Certificate): string; + pktostr: fn (pk: ref Crypt->PK, owner: string): string; + sktostr: fn (sk: ref Crypt->SK, owner: string): string; + + # parse text into types + strtocert: fn (s: string): ref Certificate; + strtopk: fn (s: string): (ref Crypt->PK, string); + strtosk: fn (s: string): (ref Crypt->SK, string); + + # create and verify Certificates + sign: fn (sk: ref Crypt->SK, signer: string, exp: int, state: ref Crypt->DigestState, ha: string): + ref Certificate; + verify: fn (pk: ref Crypt->PK, cert: ref Certificate, state: ref Crypt->DigestState): + int; +}; |
