summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--appl/lib/mkfile2
-rw-r--r--appl/lib/oldauth.b344
-rw-r--r--dis/lib/oldauth.disbin0 -> 6456 bytes
-rw-r--r--man/2/security-oldauth246
-rw-r--r--module/oldauth.m48
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
new file mode 100644
index 00000000..10481a49
--- /dev/null
+++ b/dis/lib/oldauth.dis
Binary files differ
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;
+};