code: purgatorio

ref: d916a4c3823f55227ffae35738c2497256e307b5
dir: /appl/cmd/auth/factotum/proto/rsa.b/

View raw version
implement Authproto;

# SSH RSA authentication.
#
# Client protocol:
#	read public key
#		if you don't like it, read another, repeat
#	write challenge
#	read response
# all numbers are hexadecimal biginits parsable with strtomp.
#

include "sys.m";
	sys: Sys;
	Rread, Rwrite: import Sys;

include "draw.m";

include "keyring.m";
	kr: Keyring;
	IPint, RSAsk, RSApk: import kr;

include "../authio.m";
	authio: Authio;
	Aattr, Aval, Aquery: import Authio;
	Attr, IO, Key, Authinfo: import authio;
	eqbytes, memrandom: import authio;
	lookattrval: import authio;


init(f: Authio): string
{
	authio = f;
	sys = load Sys Sys->PATH;
	kr = load Keyring Keyring->PATH;
#	base16 = load Encoding Encoding->BASE16PATH;
	return nil;
}

interaction(attrs: list of ref Attr, io: ref IO): string
{
	role := lookattrval(attrs, "role");
	if(role == nil)
		return "role not specified";
	if(role != "client")
		return "only client role supported";
	sk: ref RSAsk;
	keys: list of ref Key;
	err: string;
	for(;;){
		waitread(io);
		(keys, err) = io.findkeys(attrs, "");
		if(keys != nil)
			break;
		io.error(err);
	}
	for(; keys != nil; keys = tl keys){
		(sk, err) = keytorsa(hd keys);
		if(sk != nil){
			r := array of byte sk.pk.n.iptostr(16);
			while(!io.reply2read(r, len r))
				waitread(io);
			data := io.rdwr();
			if(data != nil){
				chal := IPint.strtoip(string data, 16);
				if(chal == nil){
					io.error("invalid challenge value");
					continue;
				}
				m := sk.decrypt(chal);
				b := array of byte m.iptostr(16);
				io.write(b, len b);
				io.done(nil);
				return nil;
			}
		}
	}
	for(;;){
		io.error("no key matches "+authio->attrtext(attrs));
		waitread(io);
	}
}

waitread(io: ref IO)
{
	while(io.rdwr() != nil)
		io.error("no current key");
}

Badkey: exception(string);

ipint(attrs: list of ref Attr, name: string): ref IPint raises Badkey
{
	s := lookattrval(attrs, name);
	if(s == nil)
		raise Badkey("missing attribute "+name);
	m := IPint.strtoip(s, 16);
	if(m == nil)
		raise Badkey("invalid value for "+name);
	return m;
}

keytorsa(k: ref Key): (ref RSAsk, string)
{
	sk := ref RSAsk;
	sk.pk = ref RSApk;
	{
		sk.pk.ek = ipint(k.attrs, "ek");
		sk.pk.n = ipint(k.attrs, "n");
		sk.dk = ipint(k.secrets, "!dk");
		sk.p = ipint(k.secrets, "!p");
		sk.q = ipint(k.secrets, "!q");
		sk.kp = ipint(k.secrets, "!kp");
		sk.kq = ipint(k.secrets, "!kq");
		sk.c2 = ipint(k.secrets, "!c2");
	}exception e{
	Badkey =>
		return (nil, "rsa key "+e);
	}
	return (sk, nil);
}

keycheck(k: ref Authio->Key): string
{
	return keytorsa(k).t1;
}