diff options
| author | Charles.Forsyth <devnull@localhost> | 2008-10-21 21:53:53 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2008-10-21 21:53:53 +0000 |
| commit | bb0454063029bcd36bb713dc95bbce4c4fa43510 (patch) | |
| tree | 4dbf3828724c2b3a43af70f855dd04ad726a3706 | |
| parent | 7bd3b6e428a8af0be5091e7ff22b07481debdf97 (diff) | |
20081021-2253
| -rw-r--r-- | CHANGES | 3 | ||||
| -rw-r--r-- | appl/cmd/auth/ai2key.b | 144 | ||||
| -rw-r--r-- | appl/cmd/auth/factotum/proto/infauth.b | 66 | ||||
| -rw-r--r-- | appl/cmd/auth/mkfile | 1 | ||||
| -rw-r--r-- | dis/auth/ai2key.dis | bin | 0 -> 2710 bytes | |||
| -rw-r--r-- | dis/auth/proto/infauth.dis | bin | 7727 -> 8649 bytes | |||
| -rw-r--r-- | libinterp/keyring.c | 2 | ||||
| -rw-r--r-- | man/8/INDEX | 3 | ||||
| -rw-r--r-- | man/8/ai2key | 262 |
9 files changed, 468 insertions, 13 deletions
@@ -1,3 +1,6 @@ +20081021 + /appl/cmd/auth/ai2key.b new command to convert authinfo files to factotum keys + /appl/cmd/auth/factotum/proto/infauth.b allow new key format 20081019 /appl/cmd/man2html.b implement "\ " => " " /man/3/prog change way a literal " was formatted diff --git a/appl/cmd/auth/ai2key.b b/appl/cmd/auth/ai2key.b new file mode 100644 index 00000000..aff86d57 --- /dev/null +++ b/appl/cmd/auth/ai2key.b @@ -0,0 +1,144 @@ +implement Ai2fact; + +# authinfo to factotum key set +# intermediate version, for use until revised Inferno authentication is ready + + +# converts an old authinfo entry in keyring directory to a key for factotum +# +# keys are in proto=infauth, and include the data for the signed certificate, and the diffie-helman parameters + +include "sys.m"; + sys: Sys; + +include "draw.m"; + +include "keyring.m"; + keyring: Keyring; + Certificate, IPint, PK, SK: import keyring; + +include "daytime.m"; + daytime: Daytime; + +include "arg.m"; + +Ai2fact: module +{ + init: fn(nil: ref Draw->Context, nil: list of string); +}; + +init(nil: ref Draw->Context, args: list of string) +{ + sys = load Sys Sys->PATH; + keyring = load Keyring Keyring->PATH; + daytime = load Daytime Daytime->PATH; + + arg := load Arg Arg->PATH; + arg->init(args); + arg->setusage("ai2key [-t 'attr=value attr=value ...'] keyfile ..."); + tag: string; + while((o := arg->opt()) != 0) + case o { + 't' => + tag = arg->earg(); + * => + arg->usage(); + } + args = arg->argv(); + if(args == nil) + arg->usage(); + arg = nil; + + now := daytime->now(); + for(; args != nil; args = tl args){ + keyfile := hd args; + ai := keyring->readauthinfo(keyfile); + if(ai == nil) + error(sys->sprint("cannot read %s: %r", keyfile)); + if(ai.cert.exp != 0 && ai.cert.exp <= now){ + sys->fprint(sys->fildes(2), "ai2key: %s: certificate expired -- key ignored\n", keyfile); + continue; + } + + if(ai.cert.exp != 0) + expires := sys->sprint(" expires=%ud", ai.cert.exp); + ha := ai.cert.ha; + if(ha == "sha") + ha = "sha1"; + + if(tag != nil) + tag = " "+tag; + + sys->print("key proto=infauth%s %s sigalg=%s-%s user=%q signer=%q pk=%s !sk=%s spk=%s cert=%s dh-alpha=%s dh-p=%s%s\n", + tag, locations(filename(keyfile)), ai.cert.sa.name, ha, ai.mypk.owner, ai.spk.owner, pktostr(ai.mypk), sktostr(ai.mysk), + pktostr(ai.spk), certtostr(ai.cert), ai.alpha.iptostr(16), ai.p.iptostr(16), expires); + } +} + +error(e: string) +{ + sys->fprint(sys->fildes(2), "ai2key: %s\n", e); + raise "fail:error"; +} + +filename(s: string): string +{ + (nil, fld) := sys->tokenize(s, "/"); + for(; fld != nil && tl fld != nil; fld = tl fld){ + # skip + } + return hd fld; +} + +# guess plausible domain, server and service attributes from the file name +locations(file: string): string +{ + if(file == "default") + return "dom=* server=*"; + (nf, flds) := sys->tokenize(file, "!"); + case nf { + * => + return sys->sprint("%s", server(file)); + 2 => + return sys->sprint("%s", server(hd tl flds)); + 3 => + # ignore network component + return sys->sprint("%s service=%q", server(hd tl flds), hd tl tl flds); + } +} + +server(name: string): string +{ + # if the name contains dot(s), we'll treat it as a domain name + if(sys->tokenize(name, ".").t0 > 1) + return sys->sprint("dom=%q server=%q", name, name); + return sys->sprint("server=%q", name); +} + +certtostr(c: ref Certificate): string +{ + return dnl(keyring->certtostr(c)); +} + +pktostr(pk: ref PK): string +{ + return dnl(keyring->pktostr(pk)); +} + +sktostr(sk: ref SK): string +{ + return dnl(keyring->sktostr(sk)); +} + +dnl(s: string): string +{ + for(i := 0; i < len s; i++) + if(s[i] == '\n') + s[i] = '^'; + while(--i > 0 && s[i] == '^'){ + # skip + } + if(i != len s) + return s[0: i+1]; + return s; +} diff --git a/appl/cmd/auth/factotum/proto/infauth.b b/appl/cmd/auth/factotum/proto/infauth.b index cfc847eb..e9b87553 100644 --- a/appl/cmd/auth/factotum/proto/infauth.b +++ b/appl/cmd/auth/factotum/proto/infauth.b @@ -139,9 +139,8 @@ interaction(attrs: list of ref Attr, io: ref IO): string senderr(io, e); break; Error1 => - senderr(io, "missing your authentication data"); - x: string = e; - return "remote: "+x; + senderr(io, "failed"); # acknowledge error + return remote(e); } { @@ -151,8 +150,7 @@ interaction(attrs: list of ref Attr, io: ref IO): string Error0 => return e; Error1 => - x: string = e; - return "remote: "+x; + return remote(e); } if(err != nil) return err; @@ -160,13 +158,26 @@ interaction(attrs: list of ref Attr, io: ref IO): string return negotiatecrypto(io, key, ai, rattrs); } +remote(s: string): string +{ + # account for strange earlier interface + if(len s < 6 || s[0: 6] != "remote") + return "remote: "+s; + return s; +} + +# TO DO: exchange attr/value pairs, covered by hmac (use part of secret up to hmac block size of 64 bytes) +# the old scheme can be distinguished either by a prefix "attrs " or simply because the string contains "=", +# and the server side can then reply. the hmac is to prevent tampering. negotiatecrypto(io: ref IO, key: ref Key, ai: ref Authinfo, attrs: list of ref Sexp): string { role := authio->lookattrval(key.attrs, "role"); alg: string; { if(role == "client"){ - alg = authio->lookattrval(key.attrs, "alg"); + alg = authio->lookattrval(key.attrs, ":alg"); + if(alg == nil) + alg = authio->lookattrval(key.attrs, "alg"); # old way if(alg == nil) alg = "md5/rc4_256"; sendmsg(io, array of byte alg); @@ -297,7 +308,8 @@ getmsg(io: ref IO): array of byte raises (Error0, Error1) if(len buf != m) raise Error0("io error: (impossible?) msg length " + string m); if(h[0] == '!'){ -sys->print("got remote error: %s, len %d\n", string buf, len string buf); + if(0) + sys->print("got remote error: %q, len %d\n", string buf, len string buf); raise Error1(string buf); } return buf; @@ -318,16 +330,46 @@ senderr(io: ref IO, e: string) io.write(buf, len buf); } +# both the s-expression and k=v form are interim, until all +# the factotum implementations can manage public keys +# the s-expression form was the original one used by Inferno factotum +# the form in which Authinfo components are separate attributes is the +# one now used by Plan 9 and Plan 9 Ports factotum implementations keytoauthinfo(key:ref Key): (ref Keyring->Authinfo, string) { - if((s := authio->lookattrval(key.secrets, "!authinfo")) == nil){ - # XXX could look up authinfo by hash at this point - return (nil, "no authinfo attribute"); - } + if((s := authio->lookattrval(key.secrets, "!authinfo")) != nil) + return strtoauthinfo(s); + # TO DO: could look up authinfo by hash + ai := ref Keyring->Authinfo; + if((s = kv(key.secrets, "!sk")) == nil || (ai.mysk = keyring->strtosk(s)) == nil) + return (nil, "bad secret key"); + if((s = kv(key.attrs, "pk")) == nil || (ai.mypk = keyring->strtopk(s)) == nil) + return (nil, "bad public key"); + if((s = kv(key.attrs, "cert")) == nil || (ai.cert = keyring->strtocert(s)) == nil) + return (nil, "bad certificate"); + if((s = kv(key.attrs, "spk")) == nil || (ai.spk = keyring->strtopk(s)) == nil) + return (nil, "bad signer public key"); + if((s = kv(key.attrs, "dh-alpha")) == nil || (ai.alpha = IPint.strtoip(s, 16)) == nil) + return (nil, "bad value for alpha"); + if((s = kv(key.attrs, "dh-p")) == nil || (ai.p = IPint.strtoip(s, 16)) == nil) + return (nil, "bad value for p"); + return (ai, nil); +} - return strtoauthinfo(s); +kv(a: list of ref Attr, name: string): string +{ + return rnl(authio->lookattrval(a, name)); +} + +rnl(s: string): string +{ + for(i := 0; i < len s; i++) + if(s[i] == '^') + s[i] = '\n'; + return s; } +# s-expression form strtoauthinfo(s: string): (ref Keyring->Authinfo, string) { (se, err, nil) := Sexp.parse(s); diff --git a/appl/cmd/auth/mkfile b/appl/cmd/auth/mkfile index 5782599e..71d31533 100644 --- a/appl/cmd/auth/mkfile +++ b/appl/cmd/auth/mkfile @@ -5,6 +5,7 @@ DIRS=\ TARG=\ aescbc.dis\ + ai2key.dis\ changelogin.dis\ countersigner.dis\ convpasswd.dis\ diff --git a/dis/auth/ai2key.dis b/dis/auth/ai2key.dis Binary files differnew file mode 100644 index 00000000..72e0b498 --- /dev/null +++ b/dis/auth/ai2key.dis diff --git a/dis/auth/proto/infauth.dis b/dis/auth/proto/infauth.dis Binary files differindex 53d5eb68..1efeabd5 100644 --- a/dis/auth/proto/infauth.dis +++ b/dis/auth/proto/infauth.dis diff --git a/libinterp/keyring.c b/libinterp/keyring.c index b0f0a0fa..69815282 100644 --- a/libinterp/keyring.c +++ b/libinterp/keyring.c @@ -1696,7 +1696,7 @@ if(0)print("Y"); buf[n] = 0; hiscert = strtocert(buf); if(hiscert == H){ - err = "bad certificate"; + err = "bad certificate syntax"; goto out; } certimmutable(hiscert); /* hide from the garbage collector */ diff --git a/man/8/INDEX b/man/8/INDEX index c520eacb..3c633861 100644 --- a/man/8/INDEX +++ b/man/8/INDEX @@ -1,4 +1,5 @@ intro 0intro +ai2key ai2key applylog applylog updatelog applylog bootpd bootpd @@ -15,6 +16,7 @@ csquery cs dhcp dhcp dns dns dnsquery dns +dsagen ai2key fpgaload fpgaload ftl ftl getauthinfo getauthinfo @@ -39,6 +41,7 @@ prep prep rdbgsrv rdbgsrv register register rip rip +rsagen ai2key rstyxd rstyxd styxd rstyxd shutdown shutdown diff --git a/man/8/ai2key b/man/8/ai2key new file mode 100644 index 00000000..99149b94 --- /dev/null +++ b/man/8/ai2key @@ -0,0 +1,262 @@ +.TH AI2KEY 8 +.SH NAME +ai2key, dsagen, rsagen \- generate and reformat public keys +.SH SYNOPSIS +.B ai2key +[ +.BI -t " tag" +] +.I keyfile +... +.P +.B dsagen +[ +.BI -t " tag" +] +.PP +.B rsagen +[ +.BI -b " nbits" +] [ +.BI -t " tag" +] +.SH DESCRIPTION +.IR Factotum (4) +represents public keys as lists of attribute-value pairs, each key on a single line prefixed with the string +.BR key . +.PP +.I Ai2key +converts the original Inferno representation of authentication data, +in the format defined for +.B authinfo +by +.IR keytext (6), +to an attribute-value format accepted by +.IR factotum (4) +for the +.B infauth +authentication protocol. +For each +.I keyfile +it writes a single line on standard output, containing +the following fields: +.IP +.EX +.fi +.ti -3n +key proto=infauth +[ +.I tag +] +.BI "sigalg=" pkalg - hashalg +[ +.BI dom= host +] +.BI server= host +[ +.BI service= svc +] +.BI "user=" name +.BI "signer=" name +.BI "pk=" pk +.BI "!sk=" sk +.BI spk= pk +.BI cert= cert +.BI dh-alpha= hex +.BI dh-p= hex +.EE +.PP +where +.RS +.TP 15n +.I pkalg +is +.BR dsa , +.B elgamal +or +.BR rsa +.PD 0 +.ns +.TP +.I hashalg +is +.B md5 +or +.BR sha1 +.br +.ns +.TP +.B user +is the user name associated with the key, as vouched for by the supporting +certificate +.BR cert +.br +.ns +.TP +.B signer +is the user name associated with the key that signed the certificate +.br +.ns +.TP +.B pk +is the user's public key +.br +.ns +.TP +.B !sk +is the user's private (secret) key +.br +.ns +.TP +.B spk +is the signer's public key +.br +.ns +.TP +.B cert +is the +.I certificate +.br +.ns +.TP +.BR dh-alpha ,\ dh-p +are the Diffie-Hellman parameters shared by the user and file servers. +.RE +.PD +.PP +The key is tagged by one or more of +.BR dom , +.B server +and +.BR service , +derived from the file name +.IR keyfile . +The server is +.RB ` * ' +if +.I keyfile +is +.BR default . +Otherwise +.I keyfile +has the form +.IP +[ +.IB net ! +] +.I host +[ +.BI ! srv +] +.PP +and +.B server +and +.B service +are set accordingly; +.B dom +is set if +.I host +looks like a domain name. +Key and certificate values have the form defined in +.IR keytext (6); +.I hex +is a large number in hexadecimal. +.PP +.I Dsagen +prints a randomly-generated DSA private key using the NIST-recommended algorithm. +If +.I tag +text is specified, it is printed after the +.B proto +attribute-value pair. +Typically, +.I tag +is a sequence of attribute-value comments describing the key. +A DSA key has the following attributes +.RS +.TP 8n +.B p +prime public modulus +.PD 0 +.TP +.B q +prime group order; divides +.BR p -1 +.TP +.B alpha +group generator +.TP +.B key +.BR alpha ^ !secret +mod +.B p +.TP +.B !secret +the secret exponent +.RE +.PD +.PP +.I Rsagen +prints a randomly generated RSA private key +whose +.B n +has exactly +.I nbits +(default 1024) +significant bits. +The key has the following attributes: +.RS +.TP +.B size +the number of significant bits in +.B n +.PD 0 +.TP +.B ek +the encryption exponent +.TP +.B n +the product of +.B !p +and +.B !q +.TP +.B !dk +the decryption exponent +.TP +.B !p +a large prime +.TP +.B !q +another large prime +.TP +.B "!kp\fR, \fL!kq\fR, \fL!c2 +parameters derived from the other attributes, cached to speed decryption +.RE +.PD +.PP +All the numbers in +.I dsagen +and +.I rsagen +output are in hexadecimal except RSA's +.BR size , +which is decimal. +A public key omits the attributes beginning with +.L ! . +A key may have other attributes as well, for example a +.B service +attribute identifying how this key is typically used, +but to these utilities such attributes are merely comments. +They can be provided in a +.I tag +argument. +.SH SOURCE +.B /appl/cmd/auth/ai2key.b +.br +.B /appl/cmd/auth/dsagen.b +.br +.B /appl/cmd/auth/rsagen.b +.SH "SEE ALSO" +.IR factotum (4) |
