xref: /inferno-os/appl/cmd/auth/signer.b (revision d6b4eae8eb0a5ca3119414005e483fedd63a62d6)
1implement Signer;
2
3include "sys.m";
4	sys: Sys;
5
6include "draw.m";
7
8include "keyring.m";
9	kr: Keyring;
10	IPint: import kr;
11
12include "security.m";
13	random: Random;
14
15Signer: module
16{
17	init:	fn(ctxt: ref Draw->Context, argv: list of string);
18};
19
20# size in bits of modulus for public keys
21PKmodlen:		con 512;
22
23# size in bits of modulus for diffie hellman
24DHmodlen:		con 512;
25
26stderr, stdin, stdout: ref Sys->FD;
27
28init(nil: ref Draw->Context, nil: list of string)
29{
30	sys = load Sys Sys->PATH;
31	random = load Random Random->PATH;
32	kr = load Keyring Keyring->PATH;
33
34	stdin = sys->fildes(0);
35	stdout = sys->fildes(1);
36	stderr = sys->fildes(2);
37
38	sys->pctl(Sys->FORKNS, nil);
39	if(sys->chdir("/keydb") < 0){
40		sys->fprint(stderr, "signer: no key database\n");
41		raise "fail:no keydb";
42	}
43
44	err := sign();
45	if(err != nil){
46		sys->fprint(stderr, "signer: %s\n", err);
47		raise "fail:error";
48	}
49}
50
51sign(): string
52{
53	info := signerkey("signerkey");
54	if(info == nil)
55		return "can't read key";
56
57	# send public part to client
58	mypkbuf := array of byte kr->pktostr(kr->sktopk(info.mysk));
59	kr->sendmsg(stdout, mypkbuf, len mypkbuf);
60	alphabuf := array of byte info.alpha.iptob64();
61	kr->sendmsg(stdout, alphabuf, len alphabuf);
62	pbuf := array of byte info.p.iptob64();
63	kr->sendmsg(stdout, pbuf, len pbuf);
64
65	# get client's public key
66	hisPKbuf := kr->getmsg(stdin);
67	if(hisPKbuf == nil)
68		return "caller hung up";
69	hisPK := kr->strtopk(string hisPKbuf);
70	if(hisPK == nil)
71		return "illegal caller PK";
72
73	# hash, sign, and blind
74	state := kr->sha1(hisPKbuf, len hisPKbuf, nil, nil);
75	cert := kr->sign(info.mysk, 0, state, "sha1");
76
77	# sanity clause
78	state = kr->sha1(hisPKbuf, len hisPKbuf, nil, nil);
79	if(kr->verify(info.mypk, cert, state) == 0)
80		return "bad signer certificate";
81
82	certbuf := array of byte kr->certtostr(cert);
83	blind := random->randombuf(random->ReallyRandom, len certbuf);
84	for(i := 0; i < len blind; i++)
85		certbuf[i] = certbuf[i] ^ blind[i];
86
87	# sum PKs and blinded certificate
88	state = kr->md5(mypkbuf, len mypkbuf, nil, nil);
89	kr->md5(hisPKbuf, len hisPKbuf, nil, state);
90	digest := array[Keyring->MD5dlen] of byte;
91	kr->md5(certbuf, len certbuf, digest, state);
92
93	# save sum and blinded cert in a file
94	file := "signed/"+hisPK.owner;
95	fd := sys->create(file, Sys->OWRITE, 8r600);
96	if(fd == nil)
97		return "can't create "+file+sys->sprint(": %r");
98	if(kr->sendmsg(fd, blind, len blind) < 0 ||
99	   kr->sendmsg(fd, digest, len digest) < 0){
100		sys->remove(file);
101		return "can't write "+file+sys->sprint(": %r");
102	}
103
104	# send blinded cert to client
105	kr->sendmsg(stdout, certbuf, len certbuf);
106
107	return nil;
108}
109
110signerkey(filename: string): ref Keyring->Authinfo
111{
112	info := kr->readauthinfo(filename);
113	if(info != nil)
114		return info;
115
116	# generate a local key
117	info = ref Keyring->Authinfo;
118	info.mysk = kr->genSK("elgamal", "*", PKmodlen);
119	info.mypk = kr->sktopk(info.mysk);
120	info.spk = kr->sktopk(info.mysk);
121	myPKbuf := array of byte kr->pktostr(info.mypk);
122	state := kr->sha1(myPKbuf, len myPKbuf, nil, nil);
123	info.cert = kr->sign(info.mysk, 0, state, "sha1");
124	(info.alpha, info.p) = kr->dhparams(DHmodlen);
125
126	if(kr->writeauthinfo(filename, info) < 0){
127		sys->fprint(stderr, "can't write signerkey file: %r\n");
128		return nil;
129	}
130
131	return info;
132}
133