xref: /inferno-os/appl/lib/oldauth.b (revision 1981fff245dfce579ef416fa767eb69d462039e9)
1implement Oldauth;
2
3#
4# TO DO
5#	- more error checking?
6#	- details of auth error handling
7#
8
9include "sys.m";
10	sys: Sys;
11
12include "ipints.m";
13	ipints: IPints;
14	IPint: import ipints;
15
16include "crypt.m";
17	crypt: Crypt;
18	PK, SK, PKsig: import crypt;
19
20include "msgio.m";
21	msgio: Msgio;
22
23include "oldauth.m";
24
25init()
26{
27	sys = load Sys Sys->PATH;
28	ipints = load IPints IPints->PATH;
29	crypt = load Crypt Crypt->PATH;
30	msgio = load Msgio Msgio->PATH;
31	msgio->init();
32}
33
34efmt()
35{
36	sys->werrstr("input or format error");
37}
38
39readauthinfo(filename: string): ref Authinfo
40{
41	fd := sys->open(filename, Sys->OREAD);
42	if(fd == nil)
43		return nil;
44	a := array[5] of string;
45	for(i := 0; i < len a; i++){
46		(s, err) := getstr(fd);
47		if(err != nil){
48			sys->werrstr(sys->sprint("%q: input or format error", filename));
49			return nil;
50		}
51		a[i] = s;
52	}
53	info := ref Authinfo;
54	(info.spk, nil) = strtopk(a[0]);
55	info.cert = strtocert(a[1]);
56	(info.mysk, info.owner) = strtosk(a[2]);
57	if(info.spk == nil || info.cert == nil || info.mysk == nil){
58		efmt();
59		return nil;
60	}
61	info.mypk = crypt->sktopk(info.mysk);
62	info.alpha = IPint.strtoip(a[3], 64);
63	info.p = IPint.strtoip(a[4], 64);
64	if(info.alpha == nil || info.p == nil){
65		efmt();
66		return nil;
67	}
68	return info;
69}
70
71writeauthinfo(filename: string, info: ref Authinfo): int
72{
73	if(info.alpha == nil || info.p == nil ||
74	   info.spk == nil || info.mysk == nil || info.cert == nil){
75		sys->werrstr("invalid authinfo");
76		return -1;
77	}
78	a := array[5] of string;
79	a[0] = pktostr(info.spk, info.cert.signer);	# signer's public key
80	a[1] = certtostr(info.cert);	# certificate for my public key
81	a[2] = sktostr(info.mysk, info.owner);	# my secret/public key
82	a[3] = b64(info.alpha);	# diffie hellman base
83	a[4] = b64(info.p);	# diffie hellman modulus
84	fd := sys->open(filename, Sys->OWRITE|Sys->OTRUNC);
85	if(fd == nil){
86		fd = sys->create(filename, Sys->OWRITE, 8r600);
87		if(fd == nil){
88			fd = sys->open(filename, Sys->OWRITE);
89			if(fd == nil)
90				return -1;
91		}
92	}
93	for(i := 0; i < len a; i++)
94		if(sendstr(fd, a[i]) <= 0)
95			return -1;
96	return 0;
97}
98
99sendstr(fd: ref Sys->FD, s: string): int
100{
101	a := array of byte s;
102	return msgio->sendmsg(fd, a, len a);
103}
104
105getstr(fd: ref Sys->FD): (string, string)
106{
107	b := msgio->getmsg(fd);
108	if(b == nil)
109		return (nil, sys->sprint("%r"));
110	return (string b, nil);
111}
112
113certtostr(c: ref Certificate): string
114{
115	s := sys->sprint("%s\n%s\n%s\n%ud\n", c.sa, c.ha, c.signer, c.exp);
116	pick r := c.sig {
117	RSA =>
118		s += b64(r.n)+"\n";
119	Elgamal =>
120		s += b64(r.r)+"\n"+b64(r.s)+"\n";
121	DSA =>
122		s += b64(r.r)+"\n"+b64(r.s)+"\n";
123	* =>
124		raise "unknown key type";
125	}
126	return s;
127}
128
129pktostr(pk: ref PK, owner: string): string
130{
131	pick k := pk {
132	RSA =>
133		s := sys->sprint("rsa\n%s\n", owner);
134		s += b64(k.n)+"\n"+b64(k.ek)+"\n";
135		return s;
136	Elgamal =>
137		s := sys->sprint("elgamal\n%s\n", owner);
138		s += b64(k.p)+"\n"+b64(k.alpha)+"\n"+b64(k.key)+"\n";
139		return s;
140	DSA =>
141		s := sys->sprint("dsa\n%s\n", owner);
142		s += b64(k.p)+"\n"+b64(k.q)+"\n"+b64(k.alpha)+"\n"+b64(k.key)+"\n";
143		return s;
144	* =>
145		raise "unknown key type";
146	}
147}
148
149sktostr(sk: ref SK, owner: string): string
150{
151	pick k := sk {
152	RSA =>
153		s := sys->sprint("rsa\n%s\n", owner);
154		s += b64(k.pk.n)+"\n"+b64(k.pk.ek)+"\n"+b64(k.dk)+"\n"+
155			b64(k.p)+"\n"+b64(k.q)+"\n"+
156			b64(k.kp)+"\n"+b64(k.kq)+"\n"+
157			k.c2.iptob64()+"\n";
158		return s;
159	Elgamal =>
160		pk := k.pk;
161		s := sys->sprint("elgamal\n%s\n", owner);
162		s += b64(pk.p)+"\n"+b64(pk.alpha)+"\n"+b64(pk.key)+"\n"+b64(k.secret)+"\n";
163		return s;
164	DSA =>
165		pk := k.pk;
166		s := sys->sprint("dsa\n%s\n", owner);
167		s += b64(pk.p)+"\n"+b64(pk.q)+"\n"+b64(pk.alpha)+"\n"+b64(k.secret)+"\n";
168		return s;
169	* =>
170		raise "unknown key type";
171	}
172}
173
174fields(s: string): array of string
175{
176	(nf, flds) := sys->tokenize(s, "\n^");
177	a := array[nf] of string;
178	for(i := 0; i < len a; i++){
179		a[i] = hd flds;
180		flds = tl flds;
181	}
182	return a;
183}
184
185bigs(a: array of string): array of ref IPint
186{
187	b := array[len a] of ref IPint;
188	for(i := 0; i < len b; i++){
189		b[i] = IPint.strtoip(a[i], 64);
190		if(b[i] == nil)
191			return nil;
192	}
193	return b;
194}
195
196need[T](a: array of T, min: int): int
197{
198	if(len a < min){
199		efmt();
200		return 1;
201	}
202	return 0;
203}
204
205strtocert(s: string): ref Certificate
206{
207	f := fields(s);
208	if(need(f, 4))
209		return nil;
210	sa := f[0];
211	ha := f[1];
212	signer := f[2];
213	exp := int big f[3];	# unsigned
214	b := bigs(f[4:]);
215	case f[0] {
216	"rsa" =>
217		if(need(b, 1))
218			return nil;
219		return ref Certificate(sa, ha, signer, exp, ref PKsig.RSA(b[0]));
220	"elgamal" =>
221		if(need(b, 2))
222			return nil;
223		return ref Certificate(sa, ha, signer, exp, ref PKsig.Elgamal(b[0], b[1]));
224	"dsa" =>
225		if(need(b, 2))
226			return nil;
227		return ref Certificate(sa, ha, signer, exp, ref PKsig.DSA(b[0], b[1]));
228	* =>
229		sys->werrstr("unknown algorithm: "+f[0]);
230		return nil;
231	}
232}
233
234strtopk(s: string): (ref PK, string)
235{
236	f := fields(s);
237	if(need(f, 3))
238		return (nil, "format error");
239	sa := f[0];
240	owner := f[1];
241	b := bigs(f[2:]);
242	case sa {
243	"rsa" =>
244		if(need(b, 2))
245			return (nil, "format error");
246		return (ref PK.RSA(b[0], b[1]), owner);
247	"elgamal" =>
248		if(need(b, 3))
249			return (nil, "format error");
250		return (ref PK.Elgamal(b[0], b[1], b[2]), owner);
251	"dsa" =>
252		if(need(b, 4))
253			return (nil, "format error");
254		return (ref PK.DSA(b[0], b[1], b[2], b[3]), owner);
255	* =>
256		return (nil, "unknown algorithm: "+f[0]);
257	}
258}
259
260strtosk(s: string): (ref SK, string)
261{
262	f := fields(s);
263	if(need(f, 3))
264		return (nil, "format error");
265	sa := f[0];
266	owner := f[1];
267	b := bigs(f[2:]);
268	case sa {
269	"rsa" =>
270		if(need(b, 8))
271			return (nil, "format error");
272		return (ref SK.RSA(ref PK.RSA(b[0], b[1]), b[2], b[3], b[4], b[5], b[6], b[7]), owner);
273	"elgamal" =>
274		if(need(b, 4))
275			return (nil, "format error");
276		return (ref SK.Elgamal(ref PK.Elgamal(b[0], b[1], b[2]), b[3]), owner);
277	"dsa" =>
278		if(need(b, 5))
279			return (nil, "format error");
280		return (ref SK.DSA(ref PK.DSA(b[0], b[1], b[2], b[3]), b[4]), owner);
281	* =>
282		return (nil, "unknown algorithm: "+f[0]);
283	}
284}
285
286skalg(sk: ref SK): string
287{
288	if(sk == nil)
289		return "nil";
290	case tagof sk {
291	tagof SK.RSA =>	return "rsa";
292	tagof SK.Elgamal =>	return "elgamal";
293	tagof SK.DSA =>	return "dsa";
294	* =>	return "gok";
295	}
296}
297
298sign(sk: ref SK, signer: string, exp: int, state: ref Crypt->DigestState, ha: string): ref Certificate
299{
300	# add signer name and expiration time to hash
301	if(state == nil)
302		return nil;
303	a := sys->aprint("%s %d", signer, exp);
304	digest := hash(ha, a, state);
305	if(digest == nil)
306		return nil;
307	b := IPint.bebytestoip(digest);
308	return ref Certificate(skalg(sk), ha, signer, exp, crypt->sign(sk, b));
309}
310
311verify(pk: ref PK, cert: ref Certificate, state: ref Crypt->DigestState): int
312{
313	if(state == nil)
314		return 0;
315	a := sys->aprint("%s %d", cert.signer, cert.exp);
316	digest := hash(cert.ha, a, state);
317	if(digest == nil)
318		return 0;
319	b := IPint.bebytestoip(digest);
320	return crypt->verify(pk, cert.sig, b);
321}
322
323hash(ha: string, a: array of byte, state: ref Crypt->DigestState): array of byte
324{
325	digest: array of byte;
326	case ha {
327	"sha" or "sha1" =>
328		digest = array[Crypt->SHA1dlen] of byte;
329		crypt->sha1(a, len a, digest, state);
330	"md5" =>
331		digest = array[Crypt->MD5dlen] of byte;
332		crypt->md5(a, len a, digest, state);
333	* =>
334		# don't bother with md4
335		sys->werrstr("unimplemented algorithm: "+ha);
336		return nil;
337	}
338	return digest;
339}
340
341b64(ip: ref IPint): string
342{
343	return ip.iptob64z();
344}
345