1implement Ai2fact; 2 3# authinfo to factotum key set 4# intermediate version, for use until revised Inferno authentication is ready 5 6 7# converts an old authinfo entry in keyring directory to a key for factotum 8# 9# keys are in proto=infauth, and include the data for the signed certificate, and the diffie-helman parameters 10 11include "sys.m"; 12 sys: Sys; 13 14include "draw.m"; 15 16include "keyring.m"; 17 keyring: Keyring; 18 Certificate, IPint, PK, SK: import keyring; 19 20include "daytime.m"; 21 daytime: Daytime; 22 23include "arg.m"; 24 25Ai2fact: module 26{ 27 init: fn(nil: ref Draw->Context, nil: list of string); 28}; 29 30init(nil: ref Draw->Context, args: list of string) 31{ 32 sys = load Sys Sys->PATH; 33 keyring = load Keyring Keyring->PATH; 34 daytime = load Daytime Daytime->PATH; 35 36 arg := load Arg Arg->PATH; 37 arg->init(args); 38 arg->setusage("ai2key [-t 'attr=value attr=value ...'] keyfile ..."); 39 tag: string; 40 while((o := arg->opt()) != 0) 41 case o { 42 't' => 43 tag = arg->earg(); 44 * => 45 arg->usage(); 46 } 47 args = arg->argv(); 48 if(args == nil) 49 arg->usage(); 50 arg = nil; 51 52 now := daytime->now(); 53 for(; args != nil; args = tl args){ 54 keyfile := hd args; 55 ai := keyring->readauthinfo(keyfile); 56 if(ai == nil) 57 error(sys->sprint("cannot read %s: %r", keyfile)); 58 if(ai.cert.exp != 0 && ai.cert.exp <= now){ 59 sys->fprint(sys->fildes(2), "ai2key: %s: certificate expired -- key ignored\n", keyfile); 60 continue; 61 } 62 63 if(ai.cert.exp != 0) 64 expires := sys->sprint(" expires=%ud", ai.cert.exp); 65 ha := ai.cert.ha; 66 if(ha == "sha") 67 ha = "sha1"; 68 69 if(tag != nil) 70 tag = " "+tag; 71 72 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", 73 tag, locations(filename(keyfile)), ai.cert.sa.name, ha, ai.mypk.owner, ai.spk.owner, pktostr(ai.mypk), sktostr(ai.mysk), 74 pktostr(ai.spk), certtostr(ai.cert), ai.alpha.iptostr(16), ai.p.iptostr(16), expires); 75 } 76} 77 78error(e: string) 79{ 80 sys->fprint(sys->fildes(2), "ai2key: %s\n", e); 81 raise "fail:error"; 82} 83 84filename(s: string): string 85{ 86 (nil, fld) := sys->tokenize(s, "/"); 87 for(; fld != nil && tl fld != nil; fld = tl fld){ 88 # skip 89 } 90 return hd fld; 91} 92 93# guess plausible domain, server and service attributes from the file name 94locations(file: string): string 95{ 96 if(file == "default") 97 return "dom=* server=*"; 98 (nf, flds) := sys->tokenize(file, "!"); 99 case nf { 100 * => 101 return sys->sprint("%s", server(file)); 102 2 => 103 return sys->sprint("%s", server(hd tl flds)); 104 3 => 105 # ignore network component 106 return sys->sprint("%s service=%q", server(hd tl flds), hd tl tl flds); 107 } 108} 109 110server(name: string): string 111{ 112 # if the name contains dot(s), we'll treat it as a domain name 113 if(sys->tokenize(name, ".").t0 > 1) 114 return sys->sprint("dom=%q server=%q", name, name); 115 return sys->sprint("server=%q", name); 116} 117 118certtostr(c: ref Certificate): string 119{ 120 return dnl(keyring->certtostr(c)); 121} 122 123pktostr(pk: ref PK): string 124{ 125 return dnl(keyring->pktostr(pk)); 126} 127 128sktostr(sk: ref SK): string 129{ 130 return dnl(keyring->sktostr(sk)); 131} 132 133dnl(s: string): string 134{ 135 for(i := 0; i < len s; i++) 136 if(s[i] == '\n') 137 s[i] = '^'; 138 while(--i > 0 && s[i] == '^'){ 139 # skip 140 } 141 if(i != len s) 142 return s[0: i+1]; 143 return s; 144} 145