summaryrefslogtreecommitdiff
path: root/appl
diff options
context:
space:
mode:
Diffstat (limited to 'appl')
-rw-r--r--appl/cmd/auth/dsagen.b14
-rw-r--r--appl/cmd/auth/factotum/proto/rsa.b64
-rw-r--r--appl/cmd/auth/getpk.b32
-rw-r--r--appl/cmd/auth/rsagen.b44
-rw-r--r--appl/cmd/auth/signer.b83
-rw-r--r--appl/cmd/auth/verify.b13
-rw-r--r--appl/cmd/cpu.b27
-rw-r--r--appl/cmd/dial.b12
-rw-r--r--appl/cmd/listen.b33
-rw-r--r--appl/cmd/sh/mpexpr.b10
-rw-r--r--appl/cmd/spki/verify.b10
-rw-r--r--appl/cmd/ssh/authpassword.b68
-rw-r--r--appl/cmd/ssh/authrsa.b188
-rw-r--r--appl/cmd/ssh/authtis.b119
-rw-r--r--appl/cmd/ssh/cipher3des.b51
-rw-r--r--appl/cmd/ssh/cipherblowfish.b43
-rw-r--r--appl/cmd/ssh/cipherdes.b43
-rw-r--r--appl/cmd/ssh/ciphernone.b28
-rw-r--r--appl/cmd/ssh/cipherrc4.b46
-rw-r--r--appl/cmd/ssh/mkfile29
-rw-r--r--appl/cmd/ssh/sshio.b586
-rw-r--r--appl/cmd/ssh/sshio.m194
-rw-r--r--appl/cmd/ssh/sshserve.b495
-rw-r--r--appl/cmd/styxlisten.b34
-rw-r--r--appl/lib/factotum.b31
-rw-r--r--appl/lib/spki/spki.b536
-rw-r--r--appl/lib/spki/verifier.b6
27 files changed, 2359 insertions, 480 deletions
diff --git a/appl/cmd/auth/dsagen.b b/appl/cmd/auth/dsagen.b
index 3e24df2f..51b50a12 100644
--- a/appl/cmd/auth/dsagen.b
+++ b/appl/cmd/auth/dsagen.b
@@ -5,9 +5,12 @@ include "sys.m";
include "draw.m";
-include "keyring.m";
- kr: Keyring;
- IPint, DSAsk, DSApk, DSAsig: import kr;
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
include "arg.m";
@@ -19,7 +22,8 @@ Dsagen: module
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
- kr = load Keyring Keyring->PATH;
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
arg := load Arg Arg->PATH;
arg->init(args);
@@ -37,7 +41,7 @@ init(nil: ref Draw->Context, args: list of string)
arg->usage();
arg = nil;
- sk := DSAsk.gen(nil);
+ sk := crypt->dsagen(nil);
if(tag != nil)
tag = " "+tag;
s := add("p", sk.pk.p);
diff --git a/appl/cmd/auth/factotum/proto/rsa.b b/appl/cmd/auth/factotum/proto/rsa.b
index 24dcef43..8af64578 100644
--- a/appl/cmd/auth/factotum/proto/rsa.b
+++ b/appl/cmd/auth/factotum/proto/rsa.b
@@ -1,6 +1,10 @@
implement Authproto;
-# SSH RSA authentication.
+# SSH RSA authentication
+#
+# this version is compatible with Plan 9 factotum
+# Plan 9 port's factotum works differently, and eventually
+# we'll support both (the role= attribute distinguishes the cases), but not today
#
# Client protocol:
# read public key
@@ -16,35 +20,38 @@ include "sys.m";
include "draw.m";
-include "keyring.m";
- kr: Keyring;
- IPint, RSAsk, RSApk: import kr;
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+include "crypt.m";
+ crypt: Crypt;
+ SK, PK: import crypt;
include "../authio.m";
authio: Authio;
Aattr, Aval, Aquery: import Authio;
- Attr, IO, Key, Authinfo: import authio;
+ Attr, IO, Key: import authio;
eqbytes, memrandom: import authio;
- lookattrval: import authio;
+ findattrval: import authio;
init(f: Authio): string
{
authio = f;
sys = load Sys Sys->PATH;
- kr = load Keyring Keyring->PATH;
-# base16 = load Encoding Encoding->BASE16PATH;
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
return nil;
}
interaction(attrs: list of ref Attr, io: ref IO): string
{
- role := lookattrval(attrs, "role");
+ role := findattrval(attrs, "role");
if(role == nil)
return "role not specified";
if(role != "client")
return "only client role supported";
- sk: ref RSAsk;
+ sk: ref SK.RSA;
keys: list of ref Key;
err: string;
for(;;){
@@ -67,7 +74,7 @@ interaction(attrs: list of ref Attr, io: ref IO): string
io.error("invalid challenge value");
continue;
}
- m := sk.decrypt(chal);
+ m := crypt->rsadecrypt(sk, chal);
b := array of byte m.iptostr(16);
io.write(b, len b);
io.done(nil);
@@ -89,30 +96,33 @@ waitread(io: ref IO)
Badkey: exception(string);
-ipint(attrs: list of ref Attr, name: string): ref IPint raises Badkey
+kv(key: ref Key, name: string): ref IPint raises Badkey
{
- s := lookattrval(attrs, name);
- if(s == nil)
+ if(name[0] == '!')
+ a := authio->findattrval(key.secrets, name);
+ else
+ a = authio->findattrval(key.attrs, name);
+ if(a == nil)
raise Badkey("missing attribute "+name);
- m := IPint.strtoip(s, 16);
+ m := IPint.strtoip(a, 16);
if(m == nil)
- raise Badkey("invalid value for "+name);
+ raise Badkey("bad value for "+name);
return m;
}
-keytorsa(k: ref Key): (ref RSAsk, string)
+keytorsa(k: ref Key): (ref SK.RSA, string)
{
- sk := ref RSAsk;
- sk.pk = ref RSApk;
+ sk := ref SK.RSA;
+ sk.pk = ref PK.RSA;
{
- 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");
+ sk.pk.ek = kv(k, "ek");
+ sk.pk.n = kv(k, "n");
+ sk.dk = kv(k, "!dk");
+ sk.p = kv(k, "!p");
+ sk.q = kv(k, "!q");
+ sk.kp = kv(k, "!kp");
+ sk.kq = kv(k, "!kq");
+ sk.c2 = kv(k, "!c2");
}exception e{
Badkey =>
return (nil, "rsa key "+e);
diff --git a/appl/cmd/auth/getpk.b b/appl/cmd/auth/getpk.b
index 24283340..e2273d17 100644
--- a/appl/cmd/auth/getpk.b
+++ b/appl/cmd/auth/getpk.b
@@ -3,10 +3,14 @@ include "sys.m";
sys: Sys;
include "draw.m";
include "arg.m";
-include "keyring.m";
- keyring: Keyring;
+include "ipints.m";
+include "crypt.m";
+ crypt: Crypt;
+include "oldauth.m";
+ oldauth: Oldauth;
-Getpk: module {
+Getpk: module
+{
init: fn(nil: ref Draw->Context, argv: list of string);
};
@@ -19,14 +23,18 @@ badmodule(p: string)
init(nil: ref Draw->Context, argv: list of string)
{
sys = load Sys Sys->PATH;
- keyring = load Keyring Keyring->PATH;
- if(keyring == nil)
- badmodule(Keyring->PATH);
+ crypt = load Crypt Crypt->PATH;
+ if(crypt == nil)
+ badmodule(Crypt->PATH);
+ oldauth = load Oldauth Oldauth->PATH;
+ if(oldauth == nil)
+ badmodule(Oldauth->PATH);
+ oldauth->init();
arg := load Arg Arg->PATH;
if(arg == nil)
badmodule(Arg->PATH);
arg->init(argv);
- arg->setusage("usage: getpk [-asu] file...");
+ arg->setusage("getpk [-asu] file...");
aflag := 0;
sflag := 0;
uflag := 0;
@@ -47,7 +55,7 @@ init(nil: ref Draw->Context, argv: list of string)
arg->usage();
multi := len argv > 1;
for(; argv != nil; argv = tl argv){
- info := keyring->readauthinfo(hd argv);
+ info := oldauth->readauthinfo(hd argv);
if(info == nil){
sys->fprint(sys->fildes(2), "getpk: cannot read %s: %r\n", hd argv);
continue;
@@ -55,13 +63,13 @@ init(nil: ref Draw->Context, argv: list of string)
pk := info.mypk;
if(sflag)
pk = info.spk;
- s := keyring->pktostr(pk);
+ s := oldauth->pktostr(pk, info.owner);
if(!aflag)
s = hex(hash(s));
if(multi)
s = hd argv + ": " + s;
if(uflag)
- s += " " + pk.owner;
+ s += " " + info.owner;
sys->print("%s\n", s);
}
}
@@ -69,8 +77,8 @@ init(nil: ref Draw->Context, argv: list of string)
hash(s: string): array of byte
{
d := array of byte s;
- digest := array[Keyring->SHA1dlen] of byte;
- keyring->sha1(d, len d, digest, nil);
+ digest := array[Crypt->SHA1dlen] of byte;
+ crypt->sha1(d, len d, digest, nil);
return digest;
}
diff --git a/appl/cmd/auth/rsagen.b b/appl/cmd/auth/rsagen.b
index a1a4477c..48fcba6d 100644
--- a/appl/cmd/auth/rsagen.b
+++ b/appl/cmd/auth/rsagen.b
@@ -5,8 +5,12 @@ include "sys.m";
include "draw.m";
-include "keyring.m";
- kr: Keyring;
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
include "arg.m";
@@ -18,7 +22,8 @@ Rsagen: module
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
- kr = load Keyring Keyring->PATH;
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
arg := load Arg Arg->PATH;
arg->init(args);
@@ -43,34 +48,31 @@ init(nil: ref Draw->Context, args: list of string)
arg->usage();
arg = nil;
- sk := kr->genSK("rsa", "", nbits);
+ sk := crypt->rsagen(nbits, 6, 0);
if(sk == nil)
error("unable to generate key");
- s := kr->sktoattr(sk);
- # need to fix the attr interface so the following isn't needed:
- s = skip(s, "alg");
- s = skip(s, "owner");
if(tag != nil)
tag = " "+tag;
- a := sys->aprint("key proto=rsa%s size=%d %s\n", tag, nbits, s);
+ s := add("ek", sk.pk.ek);
+ s += add("n", sk.pk.n);
+ s += add("!dk", sk.dk);
+ s += add("!p", sk.p);
+ s += add("!q", sk.q);
+ s += add("!kp", sk.kp);
+ s += add("!kq", sk.kq);
+ s += add("!c2", sk.c2);
+ a := sys->aprint("key proto=rsa%s size=%d%s\n", tag, sk.pk.n.bits(), s);
if(sys->write(sys->fildes(1), a, len a) != len a)
error(sys->sprint("error writing key: %r"));
}
-skip(s: string, attr: string): string
-{
- for(i := 0; i < len s && s[i] != ' '; i++)
- {}
- if(i >= len s)
- return s;
- (nf, fld) := sys->tokenize(s[0:i], "=");
- if(nf == 2 && hd fld == attr)
- s = s[i+1:];
- return s;
-}
-
error(s: string)
{
sys->fprint(sys->fildes(2), "rsagen: %s\n", s);
raise "fail:error";
}
+
+add(name: string, b: ref IPint): string
+{
+ return " "+name+"="+b.iptostr(16);
+}
diff --git a/appl/cmd/auth/signer.b b/appl/cmd/auth/signer.b
index b3f4669d..b27a719c 100644
--- a/appl/cmd/auth/signer.b
+++ b/appl/cmd/auth/signer.b
@@ -5,10 +5,20 @@ include "sys.m";
include "draw.m";
-include "keyring.m";
- kr: Keyring;
- IPint: import kr;
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
+
+include "oldauth.m";
+ oldauth: Oldauth;
+include "msgio.m";
+ msgio: Msgio;
+
+include "keyring.m";
include "security.m";
random: Random;
@@ -29,7 +39,12 @@ init(nil: ref Draw->Context, nil: list of string)
{
sys = load Sys Sys->PATH;
random = load Random Random->PATH;
- kr = load Keyring Keyring->PATH;
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
+ oldauth = load Oldauth Oldauth->PATH;
+ oldauth->init();
+ msgio = load Msgio Msgio->PATH;
+ msgio->init();
stdin = sys->fildes(0);
stdout = sys->fildes(1);
@@ -55,75 +70,75 @@ sign(): string
return "can't read key";
# send public part to client
- mypkbuf := array of byte kr->pktostr(kr->sktopk(info.mysk));
- kr->sendmsg(stdout, mypkbuf, len mypkbuf);
+ mypkbuf := array of byte oldauth->pktostr(crypt->sktopk(info.mysk), info.owner);
+ msgio->sendmsg(stdout, mypkbuf, len mypkbuf);
alphabuf := array of byte info.alpha.iptob64();
- kr->sendmsg(stdout, alphabuf, len alphabuf);
+ msgio->sendmsg(stdout, alphabuf, len alphabuf);
pbuf := array of byte info.p.iptob64();
- kr->sendmsg(stdout, pbuf, len pbuf);
+ msgio->sendmsg(stdout, pbuf, len pbuf);
# get client's public key
- hisPKbuf := kr->getmsg(stdin);
+ hisPKbuf := msgio->getmsg(stdin);
if(hisPKbuf == nil)
return "caller hung up";
- hisPK := kr->strtopk(string hisPKbuf);
+ (hisPK, hisname) := oldauth->strtopk(string hisPKbuf);
if(hisPK == nil)
return "illegal caller PK";
# hash, sign, and blind
- state := kr->sha1(hisPKbuf, len hisPKbuf, nil, nil);
- cert := kr->sign(info.mysk, 0, state, "sha1");
+ state := crypt->sha1(hisPKbuf, len hisPKbuf, nil, nil);
+ cert := oldauth->sign(info.mysk, info.owner, 0, state, "sha1");
# sanity clause
- state = kr->sha1(hisPKbuf, len hisPKbuf, nil, nil);
- if(kr->verify(info.mypk, cert, state) == 0)
+ state = crypt->sha1(hisPKbuf, len hisPKbuf, nil, nil);
+ if(oldauth->verify(info.mypk, cert, state) == 0)
return "bad signer certificate";
- certbuf := array of byte kr->certtostr(cert);
+ certbuf := array of byte oldauth->certtostr(cert);
blind := random->randombuf(random->ReallyRandom, len certbuf);
for(i := 0; i < len blind; i++)
certbuf[i] = certbuf[i] ^ blind[i];
# sum PKs and blinded certificate
- state = kr->md5(mypkbuf, len mypkbuf, nil, nil);
- kr->md5(hisPKbuf, len hisPKbuf, nil, state);
+ state = crypt->md5(mypkbuf, len mypkbuf, nil, nil);
+ crypt->md5(hisPKbuf, len hisPKbuf, nil, state);
digest := array[Keyring->MD5dlen] of byte;
- kr->md5(certbuf, len certbuf, digest, state);
+ crypt->md5(certbuf, len certbuf, digest, state);
# save sum and blinded cert in a file
- file := "signed/"+hisPK.owner;
+ file := "signed/"+hisname;
fd := sys->create(file, Sys->OWRITE, 8r600);
if(fd == nil)
return "can't create "+file+sys->sprint(": %r");
- if(kr->sendmsg(fd, blind, len blind) < 0 ||
- kr->sendmsg(fd, digest, len digest) < 0){
+ if(msgio->sendmsg(fd, blind, len blind) < 0 ||
+ msgio->sendmsg(fd, digest, len digest) < 0){
sys->remove(file);
return "can't write "+file+sys->sprint(": %r");
}
# send blinded cert to client
- kr->sendmsg(stdout, certbuf, len certbuf);
+ msgio->sendmsg(stdout, certbuf, len certbuf);
return nil;
}
-signerkey(filename: string): ref Keyring->Authinfo
+signerkey(filename: string): ref Oldauth->Authinfo
{
- info := kr->readauthinfo(filename);
+ info := oldauth->readauthinfo(filename);
if(info != nil)
return info;
# generate a local key
- info = ref Keyring->Authinfo;
- info.mysk = kr->genSK("elgamal", "*", PKmodlen);
- info.mypk = kr->sktopk(info.mysk);
- info.spk = kr->sktopk(info.mysk);
- myPKbuf := array of byte kr->pktostr(info.mypk);
- state := kr->sha1(myPKbuf, len myPKbuf, nil, nil);
- info.cert = kr->sign(info.mysk, 0, state, "sha1");
- (info.alpha, info.p) = kr->dhparams(DHmodlen);
-
- if(kr->writeauthinfo(filename, info) < 0){
+ info = ref Oldauth->Authinfo;
+ info.mysk = crypt->genSK("elgamal", PKmodlen);
+ info.mypk = crypt->sktopk(info.mysk);
+ info.spk = crypt->sktopk(info.mysk);
+ myPKbuf := array of byte oldauth->pktostr(info.mypk, "*");
+ state := crypt->sha1(myPKbuf, len myPKbuf, nil, nil);
+ info.cert = oldauth->sign(info.mysk, "*", 0, state, "sha1");
+ (info.alpha, info.p) = crypt->dhparams(DHmodlen);
+
+ if(oldauth->writeauthinfo(filename, info) < 0){
sys->fprint(stderr, "can't write signerkey file: %r\n");
return nil;
}
diff --git a/appl/cmd/auth/verify.b b/appl/cmd/auth/verify.b
index d829a76c..91fe1a86 100644
--- a/appl/cmd/auth/verify.b
+++ b/appl/cmd/auth/verify.b
@@ -3,8 +3,8 @@ implement Verify;
include "sys.m";
sys: Sys;
-include "keyring.m";
- kr: Keyring;
+include "msgio.m";
+ msgio: Msgio;
include "draw.m";
@@ -25,7 +25,8 @@ pro := array[] of {
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
- kr = load Keyring Keyring->PATH;
+ msgio = load Msgio Msgio->PATH;
+ msgio->init();
stdin = sys->fildes(0);
stderr = sys->fildes(2);
@@ -50,8 +51,8 @@ init(nil: ref Draw->Context, args: list of string)
sys->fprint(stderr, "signer: can't open %s: %r\n", file);
raise "fail:no certificate";
}
- certbuf := kr->getmsg(fd);
- digest := kr->getmsg(fd);
+ certbuf := msgio->getmsg(fd);
+ digest := msgio->getmsg(fd);
if(digest == nil || certbuf == nil){
sys->fprint(stderr, "signer: can't read %s: %r\n", file);
raise "fail:bad certificate";
@@ -78,7 +79,7 @@ init(nil: ref Draw->Context, args: list of string)
sys->fprint(stderr, "signer: can't create %s: %r\n", nfile);
raise "fail:create";
}
- if(kr->sendmsg(fd, certbuf, len certbuf) < 0){
+ if(msgio->sendmsg(fd, certbuf, len certbuf) < 0){
sys->fprint(stderr, "signer: can't write %s: %r\n", nfile);
raise "fail:write";
}
diff --git a/appl/cmd/cpu.b b/appl/cmd/cpu.b
index 75728e57..8acab430 100644
--- a/appl/cmd/cpu.b
+++ b/appl/cmd/cpu.b
@@ -5,6 +5,9 @@ include "sys.m";
stderr: ref Sys->FD;
include "draw.m";
Context: import Draw;
+
+include "dial.m";
+
include "string.m";
str: String;
include "arg.m";
@@ -50,6 +53,9 @@ init(nil: ref Context, argv: list of string)
kr := load Keyring Keyring->PATH;
if (kr == nil) badmodule(Keyring->PATH);
+ dial := load Dial Dial->PATH;
+ if(dial == nil) badmodule(Dial->PATH);
+
arg->init(argv);
alg := "";
while ((opt := arg->opt()) != 0) {
@@ -79,7 +85,7 @@ init(nil: ref Context, argv: list of string)
user := getuser();
kd := "/usr/" + user + "/keyring/";
- cert := kd + netmkaddr(mach, "tcp", "");
+ cert := kd + dial->netmkaddr(mach, "tcp", "");
if (!exists(cert)) {
cert = kd + "default";
if (!exists(cert)) {
@@ -92,8 +98,8 @@ init(nil: ref Context, argv: list of string)
if(!exists("/dev/draw/new"))
sys->bind("#d", "/dev", Sys->MBEFORE);
- (ok, c) := sys->dial(netmkaddr(mach, "net", "rstyx"), nil);
- if(ok < 0){
+ c := dial->dial(dial->netmkaddr(mach, "net", "rstyx"), nil);
+ if(c == nil){
sys->fprint(stderr, "Error: cpu: dial: %r\n");
return;
}
@@ -151,18 +157,3 @@ getuser(): string
return string buf[0:n];
}
-
-netmkaddr(addr, net, svc: string): string
-{
- if(net == nil)
- net = "net";
- (n, nil) := sys->tokenize(addr, "!");
- if(n <= 1){
- if(svc== nil)
- return sys->sprint("%s!%s", net, addr);
- return sys->sprint("%s!%s!%s", net, addr, svc);
- }
- if(svc == nil || n > 2)
- return addr;
- return sys->sprint("%s!%s", addr, svc);
-}
diff --git a/appl/cmd/dial.b b/appl/cmd/dial.b
index c562a570..8821b49a 100644
--- a/appl/cmd/dial.b
+++ b/appl/cmd/dial.b
@@ -1,4 +1,4 @@
-implement Dial;
+implement Dialcmd;
include "sys.m";
sys: Sys;
include "draw.m";
@@ -7,11 +7,12 @@ include "keyring.m";
keyring: Keyring;
include "security.m";
auth: Auth;
+include "dial.m";
include "sh.m";
sh: Sh;
Context: import sh;
-Dial: module {
+Dialcmd: module {
init: fn(nil: ref Draw->Context, argv: list of string);
};
@@ -35,6 +36,9 @@ init(drawctxt: ref Draw->Context, argv: list of string)
arg := load Arg Arg->PATH;
if (arg == nil)
badmodule(Arg->PATH);
+ dial := load Dial Dial->PATH;
+ if(dial == nil)
+ badmodule(Dial->PATH);
sh = load Sh Sh->PATH;
if (sh == nil)
badmodule(Sh->PATH);
@@ -87,8 +91,8 @@ init(drawctxt: ref Draw->Context, argv: list of string)
}
}
- (ok, c) := sys->dial(addr, nil);
- if (ok == -1) {
+ c := dial->dial(addr, nil);
+ if (c == nil) {
sys->fprint(stderr(), "dial: cannot dial %s:: %r\n", addr);
raise "fail:errors";
}
diff --git a/appl/cmd/listen.b b/appl/cmd/listen.b
index 25869223..5a06892d 100644
--- a/appl/cmd/listen.b
+++ b/appl/cmd/listen.b
@@ -7,6 +7,8 @@ include "keyring.m";
keyring: Keyring;
include "security.m";
auth: Auth;
+include "dial.m";
+ dial: Dial;
include "sh.m";
sh: Sh;
Context: import sh;
@@ -31,6 +33,9 @@ init(drawctxt: ref Draw->Context, argv: list of string)
auth = load Auth Auth->PATH;
if (auth == nil)
badmodule(Auth->PATH);
+ dial = load Dial Dial->PATH;
+ if (dial == nil)
+ badmodule(Dial->PATH);
sh = load Sh Sh->PATH;
if (sh == nil)
badmodule(Sh->PATH);
@@ -120,8 +125,8 @@ listen1(drawctxt: ref Draw->Context, addr: string, argv: list of string,
sys->pctl(Sys->FORKFD, nil);
ctxt := Context.new(drawctxt);
- (ok, acon) := sys->announce(addr);
- if (ok == -1) {
+ acon := dial->announce(addr);
+ if (acon == nil) {
sys->fprint(stderr(), "listen: failed to announce on '%s': %r\n", addr);
sync <-= "cannot announce";
exit;
@@ -146,15 +151,15 @@ listen1(drawctxt: ref Draw->Context, addr: string, argv: list of string,
}
sync <-= nil;
- listench := chan of (int, Sys->Connection);
- authch := chan of (string, Sys->Connection);
+ listench := chan of ref Dial->Connection;
+ authch := chan of (string, ref Dial->Connection);
spawn listener(listench, acon, addr);
for (;;) {
user := "";
- ccon: Sys->Connection;
+ ccon: ref Dial->Connection;
alt {
- (lok, c) := <-listench =>
- if (lok == -1){
+ c := <-listench =>
+ if (c == nil){
sync <-= "listen";
exit;
}
@@ -182,13 +187,13 @@ listen1(drawctxt: ref Draw->Context, addr: string, argv: list of string,
}
}
-listener(listench: chan of (int, Sys->Connection), c: Sys->Connection, addr: string)
+listener(listench: chan of ref Dial->Connection, c: ref Dial->Connection, addr: string)
{
for (;;) {
- (ok, nc) := sys->listen(c);
- if (ok == -1) {
+ nc := dial->listen(c);
+ if (nc == nil) {
sys->fprint(stderr(), "listen: listen error on '%s': %r\n", addr);
- listench <-= (-1, nc);
+ listench <-= nc;
exit;
}
if (verbose)
@@ -200,13 +205,13 @@ listener(listench: chan of (int, Sys->Connection), c: Sys->Connection, addr: str
else{
if(nc.cfd != nil)
sys->fprint(nc.cfd, "keepalive");
- listench <-= (ok, nc);
+ listench <-= nc;
}
}
}
-authenticator(authch: chan of (string, Sys->Connection),
- c: Sys->Connection, algs: list of string, addr: string)
+authenticator(authch: chan of (string, ref Dial->Connection),
+ c: ref Dial->Connection, algs: list of string, addr: string)
{
err: string;
(c.dfd, err) = auth->server(algs, serverkey, c.dfd, 0);
diff --git a/appl/cmd/sh/mpexpr.b b/appl/cmd/sh/mpexpr.b
index 682c01e8..0aaf6cda 100644
--- a/appl/cmd/sh/mpexpr.b
+++ b/appl/cmd/sh/mpexpr.b
@@ -3,9 +3,9 @@ implement Shellbuiltin;
include "sys.m";
sys: Sys;
include "draw.m";
-include "keyring.m";
- keyring: Keyring;
- IPint: import keyring;
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
include "sh.m";
sh: Sh;
Listnode, Context: import sh;
@@ -17,7 +17,7 @@ One: Big;
initbuiltin(ctxt: ref Context, shmod: Sh): string
{
sys = load Sys Sys->PATH;
- keyring = load Keyring Keyring->PATH;
+ ipints = load IPints IPints->PATH;
sh = shmod;
myself = load Shellbuiltin "$self";
if (myself == nil)
@@ -233,7 +233,7 @@ oper(ctxt: ref Context, args: list of Big, op, lastop, lastn: int,
BITS => r = mki(n1.bits());
EXPMOD => r = n1.expmod(n2, n3);
EXP => r = n1.expmod(n2, nil);
- RAND => r = IPint.random(0, n1.iptoint());
+ RAND => r = IPint.random(n1.iptoint());
INVERT => r = n1.invert(n2);
}
return r :: stk;
diff --git a/appl/cmd/spki/verify.b b/appl/cmd/spki/verify.b
index 9eab6b41..daf563ac 100644
--- a/appl/cmd/spki/verify.b
+++ b/appl/cmd/spki/verify.b
@@ -11,9 +11,11 @@ include "sys.m";
include "draw.m";
-include "keyring.m";
- kr: Keyring;
- IPint: import kr;
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
include "bufio.m";
bufio: Bufio;
@@ -44,7 +46,7 @@ debug := 0;
init(nil: ref Draw->Context, args: list of string)
{
sys = load Sys Sys->PATH;
- kr = load Keyring Keyring->PATH;
+ ipints = load IPints IPints->PATH;
bufio = load Bufio Bufio->PATH;
sexprs = load Sexprs Sexprs->PATH;
spki = load SPKI SPKI->PATH;
diff --git a/appl/cmd/ssh/authpassword.b b/appl/cmd/ssh/authpassword.b
new file mode 100644
index 00000000..1a149117
--- /dev/null
+++ b/appl/cmd/ssh/authpassword.b
@@ -0,0 +1,68 @@
+implement Auth;
+
+include "sys.m";
+ sys: Sys;
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt; # TO DO: needed to avoid compiler error
+
+include "factotum.m";
+ factotum: Factotum;
+
+include "sshio.m";
+ sshio: Sshio;
+ Conn, Msg: import sshio;
+
+id(): int
+{
+ return SSH_AUTH_PASSWORD;
+}
+
+init(mod: Sshio)
+{
+ sys = load Sys Sys->PATH;
+ sshio = mod;
+}
+
+firstmsg(): int
+{
+ return SSH_CMSG_AUTH_PASSWORD;
+}
+
+authsrv(c: ref Conn, m: ref Msg): ref AuthInfo
+{
+ pass := m.getstring();
+# return auth_userpasswd(c.user, pass);
+ return ref AuthInfo(c.user, nil); # TO DO:
+}
+
+auth(c: ref Conn): int
+{
+ if(factotum == nil)
+ factotum = load Factotum Factotum->PATH;
+ (user, pass) := factotum->getuserpasswd(sys->sprint("proto=pass service=ssh server=%q user=%q", c.host, c.user));
+ if(user == nil){
+ sshio->debug(DBG_AUTH, "getuserpasswd failed");
+ return -1;
+ }
+
+ sshio->debug(DBG_AUTH, "try using password from factotum\n");
+ m := Msg.mk(SSH_CMSG_AUTH_PASSWORD, 4+Sys->UTFmax*len pass);
+ m.putstring(pass);
+ c.out <-= m;
+
+ m = sshio->recvmsg(c, -1);
+ case m.mtype {
+ SSH_SMSG_SUCCESS =>
+ return 0;
+ SSH_SMSG_FAILURE =>
+ return -1;
+ * =>
+ sshio->badmsg(m, 0, nil);
+ return -1;
+ }
+}
diff --git a/appl/cmd/ssh/authrsa.b b/appl/cmd/ssh/authrsa.b
new file mode 100644
index 00000000..427355d5
--- /dev/null
+++ b/appl/cmd/ssh/authrsa.b
@@ -0,0 +1,188 @@
+implement Auth;
+
+include "sys.m";
+ sys: Sys;
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
+ PK, SK: import crypt;
+
+include "factotum.m";
+ factotum: Factotum;
+ Attr: import factotum;
+ findattrval: import factotum;
+
+include "sshio.m";
+ sshio: Sshio;
+ Conn, Msg: import sshio;
+ debug: import sshio;
+
+id(): int
+{
+ return SSH_AUTH_RSA;
+}
+
+init(mod: Sshio)
+{
+ sshio = mod;
+ sys = load Sys Sys->PATH;
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
+ factotum = load Factotum Factotum->PATH;
+ factotum->init();
+}
+
+firstmsg(): int
+{
+ return SSH_CMSG_AUTH_RSA;
+}
+
+authsrv(c: ref Conn, m: ref Msg): ref AuthInfo
+{
+ # TO DO: use factotum
+ hismod := m.getipint();
+ if(hismod.bits() < 512){
+ debug(DBG_AUTH, sys->sprint("rsa key for %s < 512 bits\n", c.user));
+ return nil;
+ }
+ hispk := readpk("/keydb/ssh/"+c.user);
+ if(hispk == nil){
+ debug(DBG_AUTH, sys->sprint("no ssh/rsa key for %s: %r\n", c.user));
+ return nil;
+ }
+ if(!hispk.n.eq(hismod)){
+ debug(DBG_AUTH, sys->sprint("%s rsa key doesn't match modulus\n", c.user));
+ return nil;
+ }
+ # encrypt a challenge with his pk
+# chal := IPint.random(256).expmod(IPint.inttoip(1), hismod);
+ chal := IPint.random(256);
+ echal := crypt->rsaencrypt(hispk, x := sshio->rsapad(chal, (hispk.n.bits()+7)/8));
+debug(DBG_AUTH, sys->sprint("padded %s\nrsa chal %s\n", x.iptostr(16), echal.iptostr(16)));
+ m = Msg.mk(SSH_SMSG_AUTH_RSA_CHALLENGE, 2048);
+ m.putipint(echal);
+ c.out <-= m;
+
+ m = sshio->recvmsg(c, SSH_CMSG_AUTH_RSA_RESPONSE);
+ response := m.getbytes(Crypt->MD5dlen);
+ chalbuf := array[32+SESSIDLEN] of byte;
+ sshio->iptorjustbe(chal, chalbuf, 32);
+ debug(DBG_AUTH, sys->sprint("\trjusted %s\n", sshio->hex(chalbuf[0:32])));
+ chalbuf[32:] = c.sessid[0: SESSIDLEN];
+ debug(DBG_AUTH, sys->sprint("\tappend sessid %s\n", sshio->hex(chalbuf)));
+ expected := array[Crypt->MD5dlen] of byte;
+ crypt->md5(chalbuf, 32+SESSIDLEN, expected, nil);
+ if(sshio->eqbytes(expected, response, len expected))
+ return ref AuthInfo(c.user, nil);
+ return nil;
+}
+
+readpk(file: string): ref PK.RSA
+{
+ fd := sys->open(file, Sys->OREAD);
+ if(fd == nil)
+ return nil;
+ buf := array[8192] of byte;
+ nr := sys->readn(fd, buf, len buf);
+ if(nr < 0)
+ return nil;
+ attrs := factotum->parseattrs(string buf[0: nr]);
+ if(findattrval(attrs, "proto") != "rsa" ||
+ (ns := findattrval(attrs, "n")) == nil ||
+ (eks := findattrval(attrs, "ek")) == nil){
+ sys->werrstr("missing rsa key attributes");
+ return nil;
+ }
+ n := IPint.strtoip(ns, 16);
+ ek := IPint.strtoip(eks, 16);
+ if(n == nil || ek == nil){
+ sys->werrstr("invalid rsa key values");
+ return nil;
+ }
+ return ref PK.RSA(n, ek);
+}
+
+auth(c: ref Conn): int
+{
+ chalbuf := array[32+SESSIDLEN] of byte;
+ response := array[Crypt->MD5dlen] of byte;
+
+ debug(DBG_AUTH, "authrsa\n");
+
+ afd := sys->open("/mnt/factotum/rpc", Sys->ORDWR);
+ if(afd == nil){
+ debug(DBG_AUTH, sys->sprint("open /mnt/factotum/rpc: %r\n"));
+ return -1;
+ }
+ s := "proto=rsa role=client";
+ if(factotum->rpc(afd, "start", array of byte s).t0 != "ok"){
+ debug(DBG_AUTH, sys->sprint("auth_rpc start %s failed: %r\n", s));
+ return -1;
+ }
+
+ debug(DBG_AUTH, "trying factotum rsa keys\n");
+ for(;;){
+ (tag, value) := factotum->rpc(afd, "read", nil);
+ if(tag != "ok")
+ break;
+ textkey := string value;
+ sshio->debug(DBG_AUTH, sys->sprint("try %q\n", textkey));
+ mod := IPint.strtoip(textkey, 16);
+ m := Msg.mk(SSH_CMSG_AUTH_RSA, 16+(mod.bits()+7/8));
+ m.putipint(mod);
+ c.out <-= m;
+
+ m = sshio->recvmsg(c, -1);
+ case m.mtype {
+ SSH_SMSG_FAILURE =>
+ debug(DBG_AUTH, "\tnot accepted\n");
+ continue;
+ SSH_SMSG_AUTH_RSA_CHALLENGE =>
+ ;
+ * =>
+ sshio->badmsg(m, 0, nil);
+ }
+ chal := m.getipint();
+ p := chal.iptostr(16);
+ debug(DBG_AUTH, sys->sprint("\tgot challenge %s\n", p));
+ unpad: ref IPint;
+ if(factotum->rpc(afd, "write", array of byte p).t0 == "ok" &&
+ ((tag, value) = factotum->rpc(afd, "read", nil)).t0 == "ok"){
+ debug(DBG_AUTH, sys->sprint("\tfactotum said %q\n", string value));
+ decr := IPint.strtoip(string value, 16);
+ if(decr != nil){
+ debug(DBG_AUTH, sys->sprint("\tdecrypted %s\n", decr.iptostr(16)));
+ unpad = sshio->rsaunpad(decr);
+ }else
+ unpad = IPint.inttoip(0);
+ }else{
+ debug(DBG_AUTH, sys->sprint("\tauth_rpc write or read failed: %r\n"));
+ unpad = IPint.inttoip(0); # it will fail, we'll go round again
+ }
+ debug(DBG_AUTH, sys->sprint("\tunpadded %s\n", unpad.iptostr(16)));
+ sshio->iptorjustbe(unpad, chalbuf, 32);
+# debug(DBG_AUTH, sys->sprint("\trjusted %.*H\n", 32, chalbuf));
+ chalbuf[32:] = c.sessid[0: SESSIDLEN];
+# debug(DBG_AUTH, sys->sprint("\tappend sesskey %.*H\n", 32, chalbuf));
+ crypt->md5(chalbuf, 32+SESSIDLEN, response, nil);
+
+ m = Msg.mk(SSH_CMSG_AUTH_RSA_RESPONSE, Crypt->MD5dlen);
+ m.putbytes(response, Crypt->MD5dlen);
+ c.out <-= m;
+
+ m = sshio->recvmsg(c, -1);
+ case m.mtype {
+ SSH_SMSG_FAILURE =>
+ ; # retry
+ SSH_SMSG_SUCCESS =>
+ return 0;
+ * =>
+ sshio->badmsg(m, 0, nil);
+ }
+ }
+ return -1;
+}
diff --git a/appl/cmd/ssh/authtis.b b/appl/cmd/ssh/authtis.b
new file mode 100644
index 00000000..0fd5edd6
--- /dev/null
+++ b/appl/cmd/ssh/authtis.b
@@ -0,0 +1,119 @@
+implement Auth;
+
+# TO DO: add chal/resp to Factotum
+
+include "sys.m";
+ sys: Sys;
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt; # avoid compiler error
+
+include "factotum.m";
+ factotum: Factotum;
+ Attr: import factotum;
+ findattrval: import factotum;
+
+include "sshio.m";
+ sshio: Sshio;
+ Conn, Msg: import sshio;
+ debug: import sshio;
+
+id(): int
+{
+ return SSH_AUTH_TIS;
+}
+
+init(mod: Sshio)
+{
+ sshio = mod;
+ sys = load Sys Sys->PATH;
+ ipints = load IPints IPints->PATH;
+ factotum = load Factotum Factotum->PATH;
+ factotum->init();
+}
+
+firstmsg(): int
+{
+ return SSH_CMSG_AUTH_TIS;
+}
+
+authsrv(conn: ref Conn, nil: ref Msg): ref AuthInfo
+{
+ if((c := factotum->challenge(sys->sprint("proto=p9cr user=%q role=server", conn.user))) == nil){
+# sshlog("auth_challenge failed for %s", conn.user);
+ return nil;
+ }
+ s := sys->sprint("Challenge: %s\nResponse: ", c.chal);
+ m := Msg.mk(SSH_SMSG_AUTH_TIS_CHALLENGE, 4+len s);
+ m.putstring(s);
+ conn.out <-= m;
+
+ m = sshio->recvmsg(conn, 0);
+ if(m == nil)
+ return nil;
+ if(m.mtype != SSH_CMSG_AUTH_TIS_RESPONSE){
+ #
+ # apparently you can just give up on
+ # this protocol and start a new one.
+ #
+ sshio->unrecvmsg(conn, m);
+ return nil;
+ }
+
+ ai := factotum->response(c, m.getstring());
+ if(ai == nil){
+ debug(DBG_AUTH, sys->sprint("response rejected: %r\n"));
+ return nil;
+ }
+ return ref AuthInfo(ai.cuid, ai.cap);
+}
+
+auth(c: ref Conn): int
+{
+ if(!c.interactive)
+ return -1;
+
+ debug(DBG_AUTH, "try TIS\n");
+ c.out <-= Msg.mk(SSH_CMSG_AUTH_TIS, 0);
+
+ m := sshio->recvmsg(c, -1);
+ case m.mtype {
+ SSH_SMSG_FAILURE =>
+ return -1;
+ SSH_SMSG_AUTH_TIS_CHALLENGE =>
+ ;
+ * =>
+ sshio->badmsg(m, SSH_SMSG_AUTH_TIS_CHALLENGE, nil);
+ }
+
+ chal := m.getstring();
+
+ if((fd := sys->open("/dev/cons", Sys->ORDWR)) == nil)
+ sshio->error(sys->sprint("can't open /dev/cons: %r"));
+
+ sys->fprint(fd, "TIS Authentication\n%s", chal);
+ resp := array[256] of byte;
+ n := sys->read(fd, resp, len resp);
+ if(n <= 0 || resp[0] == byte '\n')
+ return -1;
+
+ m = Msg.mk(SSH_CMSG_AUTH_TIS_RESPONSE, 4+n);
+ m.put4(len resp);
+ m.putbytes(resp, n);
+ c.out <-= m;
+
+ m = sshio->recvmsg(c, -1);
+ case m.mtype {
+ SSH_SMSG_SUCCESS =>
+ return 0;
+ SSH_SMSG_FAILURE =>
+ return -1;
+ * =>
+ sshio->badmsg(m, 0, nil);
+ return -1;
+ }
+}
diff --git a/appl/cmd/ssh/cipher3des.b b/appl/cmd/ssh/cipher3des.b
new file mode 100644
index 00000000..e6f347f1
--- /dev/null
+++ b/appl/cmd/ssh/cipher3des.b
@@ -0,0 +1,51 @@
+implement Cipher;
+
+include "sys.m";
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
+ DESstate: import crypt;
+
+include "sshio.m";
+
+Cipherstate: adt
+{
+ enc: array of ref DESstate;
+ dec: array of ref DESstate;
+};
+
+cs: ref Cipherstate;
+
+id(): int
+{
+ return SSH_CIPHER_3DES;
+}
+
+init(key: array of byte, nil: int)
+{
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
+ cs = ref Cipherstate(array[3] of ref DESstate, array[3] of ref DESstate);
+ for(i := 0; i < 3; i++){
+ cs.enc[i] = crypt->dessetup(key[i*8:], nil);
+ cs.dec[i] = crypt->dessetup(key[i*8:], nil);
+ }
+}
+
+encrypt(buf: array of byte, nbuf: int)
+{
+ crypt->descbc(cs.enc[0], buf, nbuf, Crypt->Encrypt);
+ crypt->descbc(cs.enc[1], buf, nbuf, Crypt->Decrypt);
+ crypt->descbc(cs.enc[2], buf, nbuf, Crypt->Encrypt);
+}
+
+decrypt(buf: array of byte, nbuf: int)
+{
+ crypt->descbc(cs.dec[2], buf, nbuf, Crypt->Decrypt);
+ crypt->descbc(cs.dec[1], buf, nbuf, Crypt->Encrypt);
+ crypt->descbc(cs.dec[0], buf, nbuf, Crypt->Decrypt);
+}
diff --git a/appl/cmd/ssh/cipherblowfish.b b/appl/cmd/ssh/cipherblowfish.b
new file mode 100644
index 00000000..8d3b0c31
--- /dev/null
+++ b/appl/cmd/ssh/cipherblowfish.b
@@ -0,0 +1,43 @@
+implement Cipher;
+
+include "sys.m";
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
+ BFstate: import crypt;
+
+include "sshio.m";
+
+Cipherstate: adt
+{
+ enc: ref BFstate;
+ dec: ref BFstate;
+};
+
+cs: ref Cipherstate;
+
+id(): int
+{
+ return SSH_CIPHER_BLOWFISH;
+}
+
+init(key: array of byte, nil: int)
+{
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
+ cs = ref Cipherstate(crypt->blowfishsetup(key, nil), crypt->blowfishsetup(key, nil));
+}
+
+encrypt(buf: array of byte, nbuf: int)
+{
+ crypt->blowfishcbc(cs.enc, buf, nbuf, Crypt->Encrypt);
+}
+
+decrypt(buf: array of byte, nbuf: int)
+{
+ crypt->blowfishcbc(cs.dec, buf, nbuf, Crypt->Decrypt);
+}
diff --git a/appl/cmd/ssh/cipherdes.b b/appl/cmd/ssh/cipherdes.b
new file mode 100644
index 00000000..7de0a7ca
--- /dev/null
+++ b/appl/cmd/ssh/cipherdes.b
@@ -0,0 +1,43 @@
+implement Cipher;
+
+include "sys.m";
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
+ DESstate: import crypt;
+
+include "sshio.m";
+
+Cipherstate: adt
+{
+ enc: ref DESstate;
+ dec: ref DESstate;
+};
+
+cs: ref Cipherstate;
+
+id(): int
+{
+ return SSH_CIPHER_DES;
+}
+
+init(key: array of byte, nil: int)
+{
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
+ cs = ref Cipherstate(crypt->dessetup(key, nil), crypt->dessetup(key, nil));
+}
+
+encrypt(buf: array of byte, nbuf: int)
+{
+ crypt->descbc(cs.enc, buf, nbuf, Crypt->Encrypt);
+}
+
+decrypt(buf: array of byte, nbuf: int)
+{
+ crypt->descbc(cs.dec, buf, nbuf, Crypt->Decrypt);
+}
diff --git a/appl/cmd/ssh/ciphernone.b b/appl/cmd/ssh/ciphernone.b
new file mode 100644
index 00000000..01a7a1f3
--- /dev/null
+++ b/appl/cmd/ssh/ciphernone.b
@@ -0,0 +1,28 @@
+implement Cipher;
+
+include "sys.m";
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+
+include "sshio.m";
+
+id(): int
+{
+ return SSH_CIPHER_NONE;
+}
+
+init(nil: array of byte, nil: int)
+{
+}
+
+encrypt(nil: array of byte, nil: int)
+{
+}
+
+decrypt(nil: array of byte, nil: int)
+{
+}
diff --git a/appl/cmd/ssh/cipherrc4.b b/appl/cmd/ssh/cipherrc4.b
new file mode 100644
index 00000000..f43f9c8d
--- /dev/null
+++ b/appl/cmd/ssh/cipherrc4.b
@@ -0,0 +1,46 @@
+implement Cipher;
+
+include "sys.m";
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
+ RC4state: import crypt;
+
+include "sshio.m";
+
+Cipherstate: adt
+{
+ enc: ref RC4state;
+ dec: ref RC4state;
+};
+
+cs: ref Cipherstate;
+
+id(): int
+{
+ return SSH_CIPHER_RC4;
+}
+
+init(key: array of byte, isserver: int)
+{
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
+ if(isserver)
+ cs = ref Cipherstate(crypt->rc4setup(key[0:16]), crypt->rc4setup(key[16:32]));
+ else
+ cs = ref Cipherstate(crypt->rc4setup(key[16:32]), crypt->rc4setup(key[0:16]));
+}
+
+encrypt(buf: array of byte, nbuf: int)
+{
+ crypt->rc4(cs.enc, buf, nbuf);
+}
+
+decrypt(buf: array of byte, nbuf: int)
+{
+ crypt->rc4(cs.dec, buf, nbuf);
+}
diff --git a/appl/cmd/ssh/mkfile b/appl/cmd/ssh/mkfile
new file mode 100644
index 00000000..afb4c903
--- /dev/null
+++ b/appl/cmd/ssh/mkfile
@@ -0,0 +1,29 @@
+<../../../mkconfig
+
+TARG=\
+ authpassword.dis\
+ authrsa.dis\
+ authtis.dis\
+ cipher3des.dis\
+ cipherblowfish.dis\
+ cipherdes.dis\
+ ciphernone.dis\
+ cipherrc4.dis\
+ sshio.dis\
+ sshserve.dis\
+# ssh.dis\
+
+SYSMODULES=\
+ arg.m\
+ keyring.m\
+ security.m\
+ rand.m\
+ sys.m\
+ draw.m\
+
+MODULES=\
+ sshio.m\
+
+DISBIN=$ROOT/dis/ssh
+
+<$ROOT/mkfiles/mkdis
diff --git a/appl/cmd/ssh/sshio.b b/appl/cmd/ssh/sshio.b
new file mode 100644
index 00000000..942b06df
--- /dev/null
+++ b/appl/cmd/ssh/sshio.b
@@ -0,0 +1,586 @@
+implement Sshio;
+
+include "sys.m";
+ sys: Sys;
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
+ PK, SK: import crypt;
+
+include "sshio.m";
+
+include "rand.m";
+ rand: Rand;
+
+init()
+{
+ sys = load Sys Sys->PATH;
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
+ rand = load Rand Rand->PATH;
+ rand->init(sys->millisec());
+}
+
+msgnames := array[45] of {
+ "SSH_MSG_NONE", # 0
+ "SSH_MSG_DISCONNECT",
+ "SSH_SMSG_PUBLIC_KEY",
+ "SSH_CMSG_SESSION_KEY",
+ "SSH_CMSG_USER",
+ "SSH_CMSG_AUTH_RHOSTS",
+ "SSH_CMSG_AUTH_RSA",
+ "SSH_SMSG_AUTH_RSA_CHALLENGE",
+ "SSH_CMSG_AUTH_RSA_RESPONSE",
+ "SSH_CMSG_AUTH_PASSWORD",
+ "SSH_CMSG_REQUEST_PTY", # 10
+ "SSH_CMSG_WINDOW_SIZE",
+ "SSH_CMSG_EXEC_SHELL",
+ "SSH_CMSG_EXEC_CMD",
+ "SSH_SMSG_SUCCESS",
+ "SSH_SMSG_FAILURE",
+ "SSH_CMSG_STDIN_DATA",
+ "SSH_SMSG_STDOUT_DATA",
+ "SSH_SMSG_STDERR_DATA",
+ "SSH_CMSG_EOF",
+ "SSH_SMSG_EXITSTATUS", # 20
+ "SSH_MSG_CHANNEL_OPEN_CONFIRMATION",
+ "SSH_MSG_CHANNEL_OPEN_FAILURE",
+ "SSH_MSG_CHANNEL_DATA",
+ "SSH_MSG_CHANNEL_INPUT_EOF",
+ "SSH_MSG_CHANNEL_OUTPUT_CLOSED",
+ "SSH_MSG_UNIX_DOMAIN_X11_FORWARDING (obsolete)",
+ "SSH_SMSG_X11_OPEN",
+ "SSH_CMSG_PORT_FORWARD_REQUEST",
+ "SSH_MSG_PORT_OPEN",
+ "SSH_CMSG_AGENT_REQUEST_FORWARDING", # 30
+ "SSH_SMSG_AGENT_OPEN",
+ "SSH_MSG_IGNORE",
+ "SSH_CMSG_EXIT_CONFIRMATION",
+ "SSH_CMSG_X11_REQUEST_FORWARDING",
+ "SSH_CMSG_AUTH_RHOSTS_RSA",
+ "SSH_MSG_DEBUG",
+ "SSH_CMSG_REQUEST_COMPRESSION",
+ "SSH_CMSG_MAX_PACKET_SIZE",
+ "SSH_CMSG_AUTH_TIS",
+ "SSH_SMSG_AUTH_TIS_CHALLENGE", # 40
+ "SSH_CMSG_AUTH_TIS_RESPONSE",
+ "SSH_CMSG_AUTH_KERBEROS",
+ "SSH_SMSG_AUTH_KERBEROS_RESPONSE",
+ "SSH_CMSG_HAVE_KERBEROS_TGT",
+};
+
+Conn.mk(host: string, fd: ref Sys->FD): ref Conn
+{
+ c := ref Conn;
+ c.host = host;
+ c.sesskey = array[SESSKEYLEN] of byte;
+ c.sessid = array[SESSIDLEN] of byte;
+ c.in = chan of (ref Msg, string);
+ c.out = chan of ref Msg;
+ c.flags = 0;
+ c.interactive = 0;
+ sync := chan of int;
+ spawn msgreader(c, fd, sync);
+ <-sync;
+ spawn msgwriter(c, fd, sync);
+ <-sync;
+ return c;
+}
+
+Conn.setkey(c: self ref Conn, key: ref PK.RSA)
+{
+ c.hostkey = key;
+}
+
+msgreader(c: ref Conn, fd: ref Sys->FD, sync: chan of int)
+{
+ sys->pctl(Sys->NEWFD, 2 :: fd.fd :: nil);
+ sync <-= 1;
+ fd = sys->fildes(fd.fd);
+ for(;;){
+ m := readmsg(c, fd);
+ if(m == nil){
+ c.in <-= (nil, sys->sprint("%r"));
+ break;
+ }
+ debug(DBG_PROTO, sys->sprint("<-[%d] %s\n", m.ep-m.rp, m.fulltext()));
+ case m.mtype {
+ SSH_MSG_IGNORE =>
+ ;
+ SSH_MSG_DEBUG =>
+ debug(DBG_PROTO, sys->sprint("remote DEBUG: %s\n", m.getstring()));
+ * =>
+ c.in <-= (m, nil);
+ }
+ }
+}
+
+msgwriter(c: ref Conn, fd: ref Sys->FD, sync: chan of int)
+{
+ sys->pctl(Sys->NEWFD, 2 :: fd.fd :: nil);
+ sync <-= 1;
+ fd = sys->fildes(fd.fd);
+ while((m := <-c.out) != nil)
+ if(writemsg(c, m, fd) < 0){
+ while(<-c.out != nil)
+ {} # flush
+ exit;
+ }
+}
+
+#
+# read initial SSH-m.n-comment line
+#
+readversion(fd: ref Sys->FD): (int, int, string)
+{
+ buf := array[128] of byte;
+ if((n := readstrnl(fd, buf, len buf)) < 0)
+ return (-1, -1, sys->sprint("error reading version: %r"));
+ # id string is "SSH-m.n-comment". We need m=1, n>=5.
+ s := string buf[0: n];
+ (nf, fld) := sys->tokenize(s, "-\r\n");
+ if(nf < 3 || hd fld != "SSH")
+ return (-1, -1, sys->sprint("unexpected protocol reply: %s", s));
+ (nf, fld) = sys->tokenize(hd tl fld, ".");
+ if(nf < 2)
+ return (-1, -1, "invalid SSH version string in "+s);
+ return (1, int hd tl fld, s);
+}
+
+calcsessid(hostmod: ref IPint, servermod: ref IPint, cookie: array of byte): array of byte
+{
+ b1 := hostmod.iptobebytes();
+ b2 := servermod.iptobebytes();
+ buf := array[len b1+len b2+COOKIELEN] of byte;
+ buf[0:] = b1;
+ buf[len b1:] = b2;
+ buf[len b1+len b2:] = cookie[0: COOKIELEN];
+ sessid := array[Crypt->MD5dlen] of byte;
+ crypt->md5(buf, len buf, sessid, nil);
+ return sessid;
+}
+
+Msg.text(m: self ref Msg): string
+{
+ if(0 <= m.mtype && m.mtype < len msgnames)
+ return msgnames[m.mtype];
+ return sys->sprint("<unknown type %d>", m.mtype);
+}
+
+Msg.fulltext(m: self ref Msg): string
+{
+ s := m.text();
+ n := m.ep;
+ if(n > 64)
+ n = 64;
+ for(i := 0; i < n; i++)
+ s += sys->sprint(" %.2ux", int m.data[i]);
+ if(n != m.ep)
+ s += " ...";
+ return s;
+}
+
+badmsg(m: ref Msg, want: int, errmsg: string)
+{
+ if(m == nil)
+ s := sys->sprint("<early eof: %s>", errmsg);
+ else
+ s = m.text();
+ if(want)
+ error(sys->sprint("got %s message expecting %s", s, msgnames[want]));
+ error(sys->sprint("got unexpected %s message", s));
+}
+
+Msg.mk(mtype: int, length: int): ref Msg
+{
+ if(length > 256*1024)
+ raise "message too large";
+ return ref Msg(mtype, array[4+8+1+length+4] of byte, 0, 0, length);
+}
+
+# used by auth tis
+unrecvmsg(c: ref Conn, m: ref Msg)
+{
+ debug(DBG_PROTO, sys->sprint("unreceived %s len %d\n", msgnames[m.mtype], m.ep-m.rp));
+ c.unget = m;
+}
+
+readmsg(c: ref Conn, fd: ref Sys->FD): ref Msg
+{
+ if(c.unget != nil){ # TO DO: assumes state of processes ensures exclusive access
+ m := c.unget;
+ c.unget = nil;
+ return m;
+ }
+ buf := array[4] of byte;
+ if((n := sys->readn(fd, buf, len buf)) != len buf){
+ if(n < 0)
+ sys->werrstr("short net read: %r");
+ else
+ sys->werrstr("short net read");
+ return nil;
+ }
+ length := get4(buf, 0);
+ if(length < 5 || length > 256*1024){
+ sys->werrstr(sys->sprint("implausible packet length: %.8ux", length));
+ return nil;
+ }
+ pad := 8-length%8;
+ m := ref Msg(0, array[pad+length] of byte, pad, 0, pad+length-4);
+ if(sys->readn(fd, m.data, len m.data) != len m.data){
+ sys->werrstr(sys->sprint("short net read: %r"));
+ return nil;
+ }
+ if(c.cipher != nil)
+ c.cipher->decrypt(m.data, length+pad);
+ crc := sum32(0, m.data, m.ep);
+ crc0 := get4(m.data, m.ep);
+ if(crc != crc0){
+ sys->werrstr(sys->sprint("bad crc %#ux != %#ux (packet length %ud)", crc, crc0, length));
+ return nil;
+ }
+ m.mtype = int m.data[m.rp++];
+ return m;
+}
+
+recvmsg(c: ref Conn, mtype: int): ref Msg
+{
+ (m, errmsg) := <-c.in;
+ if(mtype == 0){
+ # no checking
+ }else if(mtype == -1){
+ # must not be nil
+ if(m == nil)
+ error(Ehangup);
+ }else if(m == nil || m.mtype != mtype) # must be given type
+ badmsg(m, mtype, errmsg);
+ return m;
+}
+
+writemsg(c: ref Conn, m: ref Msg, fd: ref Sys->FD): int
+{
+ datalen := m.wp;
+ length := datalen+1+4; # will add type and crc
+ pad := 8-length%8;
+ debug(DBG_PROTO, sys->sprint("->[%d] %s\n", datalen, m.fulltext()));
+ m.data[4+pad+1:] = m.data[0: datalen]; # slide data to correct position (is this guaranteed?) TO DO
+ put4(m.data, 0, length);
+ p := 4;
+ if(c.cipher != nil)
+ for(i := 0; i < pad; i++)
+ m.data[p++] = byte fastrand();
+ else{
+ for(i = 0; i < pad; i++)
+ m.data[p++] = byte 0;
+ }
+ m.data[p++] = byte m.mtype;
+ # data already in position
+ p += datalen;
+ crc := sum32(0, m.data[4:], pad+1+datalen);
+ put4(m.data, p, crc);
+ p += 4;
+ if(c.cipher != nil)
+ c.cipher->encrypt(m.data[4:], length+pad);
+ if(sys->write(fd, m.data, p) != p)
+ return -1;
+ return 0;
+}
+
+Msg.get1(m: self ref Msg): int
+{
+ if(m.rp >= m.ep)
+ raise Edecode;
+ return int m.data[m.rp++];
+}
+
+Msg.get2(m: self ref Msg): int
+{
+ if(m.rp+2 > m.ep)
+ raise Edecode;
+ x := (int m.data[m.rp+0]<<8) | int m.data[m.rp+1];
+ m.rp += 2;
+ return x;
+}
+
+Msg.get4(m: self ref Msg): int
+{
+ if(m.rp+4 > m.ep)
+ raise Edecode;
+ x := int m.data[m.rp+0]<<24|int m.data[m.rp+1]<<16|int m.data[m.rp+2]<<8|int m.data[m.rp+3];
+ m.rp += 4;
+ return x;
+}
+
+Msg.getarray(m: self ref Msg): array of byte
+{
+ length := m.get4();
+ if(m.rp+length > m.ep)
+ raise Edecode;
+ p := m.data[m.rp: m.rp+length];
+ m.rp += length;
+ return p;
+}
+
+Msg.getstring(m: self ref Msg): string
+{
+ return string m.getarray();
+}
+
+Msg.getbytes(m: self ref Msg, n: int): array of byte
+{
+ if(m.rp+n > m.ep)
+ raise Edecode;
+ p := m.data[m.rp: m.rp+n];
+ m.rp += n;
+ return p;
+}
+
+Msg.getipint(m: self ref Msg): ref IPint
+{
+ n := (m.get2()+7)/8; # get2 returns # bits
+ return IPint.bebytestoip(m.getbytes(n));
+}
+
+Msg.getpk(m: self ref Msg): ref PK.RSA
+{
+ m.get4();
+ ek := m.getipint();
+ n := m.getipint();
+ return ref PK.RSA(n, ek);
+}
+
+Msg.put1(m: self ref Msg, x: int)
+{
+ if(m.wp >= m.ep)
+ raise Eencode;
+ m.data[m.wp++] = byte x;
+}
+
+Msg.put2(m: self ref Msg, x: int)
+{
+ if(m.wp+2 > m.ep)
+ raise Eencode;
+ (m.data[m.wp+0], m.data[m.wp+1]) = (byte (x>>8), byte x);
+ m.wp += 2;
+}
+
+Msg.put4(m: self ref Msg, x: int)
+{
+ if(m.wp+4 > m.ep)
+ raise Eencode;
+ (m.data[m.wp+0], m.data[m.wp+1], m.data[m.wp+2], m.data[m.wp+3]) = (byte (x>>24), byte (x>>16), byte (x>>8), byte x);
+ m.wp += 4;
+}
+
+Msg.putstring(m: self ref Msg, s: string)
+{
+ b := array of byte s;
+ m.put4(len b);
+ m.putbytes(b, len b);
+}
+
+Msg.putbytes(m: self ref Msg, a: array of byte, n: int)
+{
+ if(m.wp+n > m.ep)
+ raise Eencode;
+ m.data[m.wp:] = a[0: n];
+ m.wp += n;
+}
+
+Msg.putipint(m: self ref Msg, b: ref IPint)
+{
+ bits := b.bits();
+ m.put2(bits);
+# n := (bits+7)/8;
+ ba := b.iptobebytes();
+ n := len ba;
+ if(m.wp+n > m.ep)
+ raise Eencode;
+ m.data[m.wp:] = ba;
+ m.wp += n;
+}
+
+Msg.putpk(m: self ref Msg, key: ref PK.RSA)
+{
+ m.put4(key.n.bits());
+ m.putipint(key.ek);
+ m.putipint(key.n);
+}
+
+crctab := array[256] of int;
+
+initsum32()
+{
+ poly := int 16redb88320;
+ for(i := 0; i < 256; i++){
+ crc := i;
+ for(j := 0; j < 8; j++)
+ if(crc&1)
+ crc = ((crc>>1) & int ~16r80000000)^poly; # need unsigned shift
+ else
+ crc = (crc>>1) & int ~16r80000000;
+ crctab[i] = crc;
+ }
+}
+
+first_38: int = 1;
+
+sum32(lcrc: int, buf: array of byte, n: int): int
+{
+ crc := lcrc;
+ if(first_38){
+ first_38 = 0;
+ initsum32();
+ }
+ s := 0;
+ while(n-- > 0)
+ crc = crctab[(crc^int buf[s++])&16rff]^((crc>>8)&int ~16rFF000000);
+ return crc;
+}
+
+erase(b: array of byte)
+{
+ for(i := 0; i < len b; i++)
+ b[i] = byte 0;
+}
+
+#
+# PKCS#1 padding
+#
+rsapad(b: ref IPint, n: int): ref IPint
+{
+ a := b.iptobebytes();
+ pad := n - len a - 3;
+ if(pad < 0)
+ error("value too large to pad"); # can't happen if keys are required size
+ buf := array[n] of byte;
+ buf[0] = byte 0;
+ buf[1] = byte 2;
+ for(i := 2; --pad >= 0; i++)
+ buf[i] = byte (1+fastrand()%255);
+ buf[i++] = byte 0;
+ buf[i:] = a;
+ c := IPint.bebytestoip(buf);
+ erase(buf);
+ erase(a);
+ return c;
+}
+
+rsaunpad(b: ref IPint): ref IPint
+{
+ buf := b.iptobebytes();
+ i := 0;
+ if(buf[0] == byte 0)
+ i++;
+ if(buf[i] != byte 2)
+ error("bad data in rsaunpad");
+ for(; i < len buf; i++)
+ if(buf[i] == byte 0)
+ break;
+ c := IPint.bebytestoip(buf[i:]);
+ erase(buf);
+ return c;
+}
+
+rsaencryptbuf(key: ref PK.RSA, buf: array of byte, nbuf: int): ref IPint
+{
+ n := (key.n.bits()+7)/8;
+ a := IPint.bebytestoip(buf[0: nbuf]);
+ b := rsapad(a, n);
+ return crypt->rsaencrypt(key, b);
+}
+
+iptorjustbe(b: ref IPint, buf: array of byte, length: int)
+{
+ a := b.iptobebytes();
+ if(len a < length){
+ length -= len a;
+ erase(buf[0: length]);
+ buf[length:] = a;
+ }else
+ buf[0:] = a[0: length];
+ erase(a);
+}
+
+hex(a: array of byte): string
+{
+ s := "";
+ for(i := 0; i < len a; i++)
+ s += sys->sprint("%.2ux", int a[i]);
+ return s;
+}
+
+debug(n: int, s: string)
+{
+ sys->fprint(sys->fildes(2), "debug: %s", s);
+}
+
+error(s: string)
+{
+ sys->fprint(sys->fildes(2), "error: %s\n", s);
+ raise "error";
+}
+
+rsagen(bits: int): ref SK.RSA
+{
+ return crypt->rsagen(bits, 6, 0);
+}
+
+rsaencrypt(key: ref PK.RSA, b: ref IPint): ref IPint
+{
+ return crypt->rsaencrypt(key, b);
+}
+
+rsadecrypt(key: ref SK.RSA, b: ref IPint): ref IPint
+{
+ return crypt->rsadecrypt(key, b);
+}
+
+fastrand(): int
+{
+ return int rand->bigrand(4294967295);
+}
+
+readstrnl(fd: ref Sys->FD, buf: array of byte, nbuf: int): int
+{
+ for(i := 0; i < nbuf; i++)
+ case sys->read(fd, buf[i:], 1) {
+ -1 =>
+ return -1;
+ 0 =>
+ sys->werrstr("unexpected EOF");
+ return -1;
+ * =>
+ if(buf[i] == byte '\n')
+ return i;
+ }
+ sys->werrstr("line too long");
+ return -1;
+}
+
+eqbytes(a: array of byte, b: array of byte, n: int): int
+{
+ if(len a > n || len b > n)
+ return 0;
+ for(i := 0; i < n; i++)
+ if(a[i] != b[i])
+ return 0;
+ return 1;
+}
+
+get4(a: array of byte, o: int): int
+{
+ return int a[o+0]<<24 | int a[o+1]<<16 | int a[o+2]<<8 | int a[o+3];
+}
+
+put4(a: array of byte, o: int, v: int)
+{
+ a[o+0] = byte (v>>24);
+ a[o+1] = byte (v>>16);
+ a[o+2] = byte (v>>8);
+ a[o+3] = byte v;
+}
diff --git a/appl/cmd/ssh/sshio.m b/appl/cmd/ssh/sshio.m
new file mode 100644
index 00000000..6c186e63
--- /dev/null
+++ b/appl/cmd/ssh/sshio.m
@@ -0,0 +1,194 @@
+
+ # internal debugging flags
+ DBG, DBG_CRYPTO, DBG_PACKET, DBG_AUTH, DBG_PROC, DBG_PROTO, DBG_IO, DBG_SCP: con 1<<iota;
+
+ # protocol packet types
+ SSH_MSG_NONE, # 0
+ SSH_MSG_DISCONNECT,
+ SSH_SMSG_PUBLIC_KEY,
+ SSH_CMSG_SESSION_KEY,
+ SSH_CMSG_USER,
+ SSH_CMSG_AUTH_RHOSTS,
+ SSH_CMSG_AUTH_RSA,
+ SSH_SMSG_AUTH_RSA_CHALLENGE,
+ SSH_CMSG_AUTH_RSA_RESPONSE,
+ SSH_CMSG_AUTH_PASSWORD, # 10
+ SSH_CMSG_REQUEST_PTY,
+ SSH_CMSG_WINDOW_SIZE,
+ SSH_CMSG_EXEC_SHELL,
+ SSH_CMSG_EXEC_CMD,
+ SSH_SMSG_SUCCESS,
+ SSH_SMSG_FAILURE,
+ SSH_CMSG_STDIN_DATA,
+ SSH_SMSG_STDOUT_DATA,
+ SSH_SMSG_STDERR_DATA,
+ SSH_CMSG_EOF, # 20
+ SSH_SMSG_EXITSTATUS,
+ SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
+ SSH_MSG_CHANNEL_OPEN_FAILURE,
+ SSH_MSG_CHANNEL_DATA,
+ SSH_MSG_CHANNEL_INPUT_EOF,
+ SSH_MSG_CHANNEL_OUTPUT_CLOSED,
+ SSH_MSG_UNIX_DOMAIN_X11_FORWARDING, # obsolete
+ SSH_SMSG_X11_OPEN,
+ SSH_CMSG_PORT_FORWARD_REQUEST,
+ SSH_MSG_PORT_OPEN, # 30
+ SSH_CMSG_AGENT_REQUEST_FORWARDING,
+ SSH_SMSG_AGENT_OPEN,
+ SSH_MSG_IGNORE,
+ SSH_CMSG_EXIT_CONFIRMATION,
+ SSH_CMSG_X11_REQUEST_FORWARDING,
+ SSH_CMSG_AUTH_RHOSTS_RSA,
+ SSH_MSG_DEBUG,
+ SSH_CMSG_REQUEST_COMPRESSION,
+ SSH_CMSG_MAX_PACKET_SIZE,
+ SSH_CMSG_AUTH_TIS, # 40
+ SSH_SMSG_AUTH_TIS_CHALLENGE,
+ SSH_CMSG_AUTH_TIS_RESPONSE,
+ SSH_CMSG_AUTH_KERBEROS,
+ SSH_SMSG_AUTH_KERBEROS_RESPONSE,
+ SSH_CMSG_HAVE_KERBEROS_TGT: con iota;
+
+ SSH_MSG_ERROR: con -1;
+
+ # protocol flags
+ SSH_PROTOFLAG_SCREEN_NUMBER: con 1<<0;
+ SSH_PROTOFLAG_HOST_IN_FWD_OPEN: con 1<<1;
+
+ # agent protocol packet types
+ SSH_AGENTC_NONE,
+ SSH_AGENTC_REQUEST_RSA_IDENTITIES,
+ SSH_AGENT_RSA_IDENTITIES_ANSWER,
+ SSH_AGENTC_RSA_CHALLENGE,
+ SSH_AGENT_RSA_RESPONSE,
+ SSH_AGENT_FAILURE,
+ SSH_AGENT_SUCCESS,
+ SSH_AGENTC_ADD_RSA_IDENTITY,
+ SSH_AGENTC_REMOVE_RSA_IDENTITY: con iota;
+
+ # protocol constants
+ SSH_MAX_DATA: con 256*1024;
+ SSH_MAX_MSG: con SSH_MAX_DATA+4;
+ SESSKEYLEN: con 32;
+ SESSIDLEN: con 16;
+ COOKIELEN: con 8;
+
+ # crypto ids
+ SSH_CIPHER_NONE,
+ SSH_CIPHER_IDEA,
+ SSH_CIPHER_DES,
+ SSH_CIPHER_3DES,
+ SSH_CIPHER_TSS,
+ SSH_CIPHER_RC4,
+ SSH_CIPHER_BLOWFISH: con iota;
+
+ # auth method ids
+ SSH_AUTH_RHOSTS,
+ SSH_AUTH_RSA,
+ SSH_AUTH_PASSWORD,
+ SSH_AUTH_RHOSTS_RSA,
+ SSH_AUTH_TIS,
+ SSH_AUTH_USER_RSA: con 1+iota;
+
+Edecode: con "error decoding input packet";
+Eencode: con "out of space encoding output packet (BUG)";
+Ehangup: con "hungup connection";
+Ememory: con "out of memory";
+
+Cipher: module
+{
+ id: fn(): int;
+ init: fn(key: array of byte, isserver: int);
+ encrypt: fn(a: array of byte, n: int);
+ decrypt: fn(a: array of byte, n: int);
+};
+
+Auth: module
+{
+ AuthInfo: adt{
+ user: string;
+ cap: string;
+ };
+
+ id: fn(): int;
+ firstmsg: fn(): int;
+ init: fn(nil: Sshio);
+ authsrv: fn(nil: ref Sshio->Conn, nil: ref Sshio->Msg): ref AuthInfo;
+ auth: fn(nil: ref Sshio->Conn): int;
+};
+
+Sshio: module
+{
+ PATH: con "sshio.dis";
+
+ Conn: adt{
+ in: chan of (ref Msg, string);
+ out: chan of ref Msg;
+
+ sessid: array of byte;
+ sesskey: array of byte;
+ hostkey: ref Crypt->PK.RSA;
+ flags: int;
+ cipher: Cipher; # chosen cipher
+ user: string;
+ host: string;
+ interactive: int;
+ unget: ref Msg;
+
+ mk: fn(host: string, fd: ref Sys->FD): ref Conn;
+ setkey: fn(c: self ref Conn, key: ref Crypt->PK.RSA);
+ };
+
+ Msg: adt{
+ mtype: int;
+ data: array of byte;
+ rp: int; # read pointer
+ wp: int; # write pointer
+ ep: int; # byte just beyond message data
+
+ mk: fn(mtype: int, length: int): ref Msg;
+ text: fn(m: self ref Msg): string;
+ fulltext: fn(m: self ref Msg): string;
+
+ get1: fn(m: self ref Msg): int;
+ get2: fn(m: self ref Msg): int;
+ get4: fn(m: self ref Msg): int;
+ getstring: fn(m: self ref Msg): string;
+ getbytes: fn(m: self ref Msg, n: int): array of byte;
+ getarray: fn(m: self ref Msg): array of byte;
+ getipint: fn(m: self ref Msg): ref IPints->IPint;
+ getpk: fn(m: self ref Msg): ref Crypt->PK.RSA;
+
+ put1: fn(m: self ref Msg, nil: int);
+ put2: fn(m: self ref Msg, nil: int);
+ put4: fn(m: self ref Msg, nil: int);
+ putstring: fn(m: self ref Msg, s: string);
+ putbytes: fn(m: self ref Msg, a: array of byte, n: int);
+ putipint: fn(m: self ref Msg, mp: ref IPints->IPint);
+ putpk: fn(m: self ref Msg, pk: ref Crypt->PK.RSA);
+ };
+
+ init: fn();
+
+ badmsg: fn(nil: ref Msg, nil: int, err: string);
+ recvmsg: fn(nil: ref Conn, nil: int): ref Msg;
+ unrecvmsg: fn(nil: ref Conn, nil: ref Msg);
+ rsapad: fn(nil: ref IPints->IPint, nil: int): ref IPints->IPint;
+ rsaunpad: fn(nil: ref IPints->IPint): ref IPints->IPint;
+ iptorjustbe: fn(nil: ref IPints->IPint, nil: array of byte, nil: int);
+ rsaencryptbuf: fn(nil: ref Crypt->PK.RSA, nil: array of byte, nil: int): ref IPints->IPint;
+ rsagen: fn(nbits: int): ref Crypt->SK.RSA;
+ rsaencrypt: fn(key: ref Crypt->PK.RSA, b: ref IPints->IPint): ref IPints->IPint;
+ rsadecrypt: fn(key: ref Crypt->SK.RSA, b: ref IPints->IPint): ref IPints->IPint;
+
+ debug: fn(nil: int, nil: string);
+ error: fn(nil: string);
+ readstrnl: fn(fd: ref Sys->FD, buf: array of byte, nbytes: int): int;
+ calcsessid: fn(hostmod: ref IPints->IPint, servermod: ref IPints->IPint, cookie: array of byte): array of byte;
+# sshlog: fn(nil: array of byte); # TBA was ...
+
+ fastrand: fn(): int;
+ eqbytes: fn(a: array of byte, b: array of byte, n: int): int;
+ readversion: fn(fd: ref Sys->FD): (int, int, string);
+ hex: fn(a: array of byte): string;
+};
diff --git a/appl/cmd/ssh/sshserve.b b/appl/cmd/ssh/sshserve.b
new file mode 100644
index 00000000..dc8bbd31
--- /dev/null
+++ b/appl/cmd/ssh/sshserve.b
@@ -0,0 +1,495 @@
+implement Sshserve;
+
+include "sys.m";
+ sys: Sys;
+
+include "draw.m";
+
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
+
+include "crypt.m";
+ crypt: Crypt;
+ PK, SK: import crypt;
+
+include "env.m";
+ env: Env;
+
+include "sh.m";
+ sh: Sh;
+
+include "wait.m";
+ wait: Wait;
+
+include "arg.m";
+
+include "sshio.m";
+ sshio: Sshio;
+ Conn, Msg: import sshio;
+ recvmsg: import sshio;
+ error, debug: import sshio;
+
+Sshserve: module
+{
+ init: fn(nil: ref Draw->Context, argl: list of string);
+};
+
+AuthRpc: adt {};
+debuglevel := 0;
+
+cipherlist := "blowfish rc4 3des";
+ciphers: list of Cipher;
+
+authlist := "rsa password tis";
+authsrvs: list of Auth;
+
+maxmsg := 256*1024;
+
+serverpriv: ref SK.RSA;
+serverkey: ref PK.RSA;
+hostpriv: ref SK.RSA;
+
+init(nil: ref Draw->Context, args: list of string)
+{
+ sys = load Sys Sys->PATH;
+ ipints = load IPints IPints->PATH;
+ crypt = load Crypt Crypt->PATH;
+ env = load Env Env->PATH;
+ sh = load Sh Sh->PATH;
+ sshio = load Sshio Sshio->PATH;
+ sshio->init();
+ wait = load Wait Wait->PATH;
+ wait->init();
+# fmtinstall('B', mpfmt);
+# fmtinstall('H', encodefmt);
+ sys->pctl(Sys->NEWPGRP|Sys->FORKFD|Sys->FORKNS|Sys->FORKENV, nil);
+ keyfile: string;
+ arg := load Arg Arg->PATH;
+ arg->setusage("sshserve [-A authlist] [-c cipherlist] [-k keyfile] client-ip-address");
+ arg->init(args);
+ while((o := arg->opt()) != 0){
+ case o {
+ 'D' =>
+ debuglevel = int arg->earg();
+ 'A' =>
+ authlist = arg->earg();
+ 'c' =>
+ cipherlist = arg->earg();
+ 'k' =>
+ keyfile = arg->earg();
+ * =>
+ arg->usage();
+ }
+ }
+ args = arg->argv();
+ if(len args != 1)
+ arg->usage();
+ arg = nil;
+
+ sys->dup(2, 1);
+# if(keyfile != nil)
+# ; # read hostpriv from file
+# sshlog("connect from %s", c.host);
+ authsrvs = loadlist("auth", authlist, authload);
+ ciphers = loadlist("cipher", cipherlist, cipherload);
+ hostpriv = crypt->rsagen(1024, 6, 0);
+ serverpriv = crypt->rsagen(768, 6, 0);
+ serverkey = serverpriv.pk;
+ {
+ versioning(sys->fildes(0));
+ c := Conn.mk(hd args, sys->fildes(0));
+ c.setkey(hostpriv.pk);
+ authenticate(c);
+ comms(c);
+ }exception e{
+ "fail:*" =>
+ raise e;
+ "error*" =>
+ notegrp(sys->pctl(0, nil), "error");
+ raise "fail:"+e;
+ }
+}
+
+authload(f: string): Auth
+{
+ return load Auth f;
+}
+
+cipherload(f: string): Cipher
+{
+ return load Cipher f;
+}
+
+loadlist[T](sort: string, set: string, loadf: ref fn(f: string): T): list of T
+{
+ l: list of T;
+ (nil, fld) := sys->tokenize(set, " \t,");
+ for(; fld != nil; fld = tl fld){
+ f := "/dis/ssh/"+sort+hd fld+".dis";
+ m := loadf(f);
+ if(m == nil)
+ error(sys->sprint("unknown %s scheme %s (%s)", sort, hd fld, f));
+ l = m :: l;
+ }
+ return l;
+}
+
+comms(c: ref Conn)
+{
+ (kidpid, infd, waiting) := prelude(c);
+Work:
+ for(;;)alt{
+ (m, nil) := <-c.in =>
+ if(m == nil){
+ notegrp(kidpid, "hungup");
+ exit;
+ }
+ case m.mtype {
+ * =>
+ sshio->badmsg(m, 0, nil);
+ SSH_MSG_DISCONNECT =>
+ notegrp(kidpid, "hungup");
+ sysfatal("client disconnected");
+ SSH_CMSG_STDIN_DATA =>
+ if(infd != nil){
+ n := m.get4();
+ sys->write(infd, m.getbytes(n), n);
+ }
+ SSH_CMSG_EOF =>
+ infd = nil;
+ SSH_CMSG_EXIT_CONFIRMATION =>
+ # sent by some clients as dying breath
+ notegrp(kidpid, "hungup");
+ break Work;
+ SSH_CMSG_WINDOW_SIZE =>
+ ; # we don't care
+ }
+ (pid, nil, status) := <-waiting =>
+ if(pid == kidpid){
+ if(status != "" && status != "0"){
+ m := Msg.mk(SSH_MSG_DISCONNECT, 4+Sys->UTFmax*len status);
+ m.putstring(status);
+ sendmsg(c, m);
+ }else{
+ m := Msg.mk(SSH_SMSG_EXITSTATUS, 4);
+ m.put4(0);
+ sendmsg(c, m);
+ }
+ sendmsg(c, nil);
+ break Work;
+ }
+ }
+ notegrp(sys->pctl(0, nil), "done");
+}
+
+prelude(c: ref Conn): (int, ref Sys->FD, chan of (int, string, string))
+{
+ for(;;){
+ m := recvmsg(c, -1);
+ if(m == nil)
+ return (-1, nil, nil);
+ case m.mtype {
+ * =>
+ sendmsg(c, Msg.mk(SSH_SMSG_FAILURE, 0));
+ SSH_MSG_DISCONNECT =>
+ sysfatal("client disconnected");
+ SSH_CMSG_REQUEST_PTY =>
+ sendmsg(c, Msg.mk(SSH_SMSG_SUCCESS, 0));
+ SSH_CMSG_MAX_PACKET_SIZE =>
+ n := m.get4();
+ if(n >= 32 && n <= SSH_MAX_MSG){
+ maxmsg = n;
+ sendmsg(c, Msg.mk(SSH_SMSG_SUCCESS, 0));
+ }else
+ sendmsg(c, Msg.mk(SSH_SMSG_FAILURE, 0));
+ SSH_CMSG_EXEC_SHELL =>
+ return startcmd(c, nil);
+ SSH_CMSG_EXEC_CMD =>
+ cmd := m.getstring();
+ return startcmd(c, cmd);
+ }
+ }
+}
+
+copyout(c: ref Conn, fd: ref Sys->FD, mtype: int)
+{
+ buf := array[8192] of byte;
+ max := len buf;
+ if(max > maxmsg-32) # 32 is an overestimate of packet overhead
+ max = maxmsg-32;
+ if(max <= 0)
+ sysfatal("maximum message size too small");
+ while((n := sys->read(fd, buf, max)) > 0){
+ m := Msg.mk(mtype, 4+n);
+ m.put4(n);
+ m.putbytes(buf, n);
+ sendmsg(c, m);
+ }
+}
+
+send_ssh_smsg_public_key(c: ref Conn, cookie: array of byte)
+{
+ m := Msg.mk(SSH_SMSG_PUBLIC_KEY, 2048);
+ m.putbytes(cookie, COOKIELEN);
+ m.putpk(serverkey);
+ m.putpk(c.hostkey);
+ m.put4(c.flags);
+ ciphermask := 0;
+ for(l1 := ciphers; l1 != nil; l1 = tl l1)
+ ciphermask |= 1<<(hd l1)->id();
+ m.put4(ciphermask);
+ authmask := 0;
+ for(l2 := authsrvs; l2 != nil; l2 = tl l2)
+ authmask |= 1<<(hd l2)->id();
+ m.put4(authmask);
+ sendmsg(c, m);
+}
+
+rpcdecrypt(rpc: ref AuthRpc, b: ref IPint): ref IPint
+{
+ raise "rpcdecrypt";
+# p := array of byte b.iptostr(16);
+# if(auth_rpc(rpc, "write", p, len p) != ARok)
+# sysfatal("factotum rsa write: %r");
+# if(auth_rpc(rpc, "read", nil, 0) != ARok)
+# sysfatal("factotum rsa read: %r");
+# return strtomp(rpc.arg, nil, 16, nil);
+}
+
+recv_ssh_cmsg_session_key(c: ref Conn, rpc: ref AuthRpc, cookie: array of byte)
+{
+ m := recvmsg(c, SSH_CMSG_SESSION_KEY);
+ id := m.get1();
+ c.cipher = nil;
+ for(l := ciphers; l != nil; l = tl l)
+ if((hd l)->id() == id){
+ c.cipher = hd l;
+ break;
+ }
+ if(c.cipher == nil)
+ sysfatal(sys->sprint("invalid cipher %d selected", id));
+ if(!sshio->eqbytes(m.getbytes(COOKIELEN), cookie, len cookie))
+ sysfatal("bad cookie");
+ serverkeylen := serverkey.n.bits();
+ hostkeylen := c.hostkey.n.bits();
+ ksmall, kbig: ref SK.RSA;
+ if(serverkeylen+128 <= hostkeylen){
+ ksmall = serverpriv;
+ kbig = nil;
+ }else if(hostkeylen+128 <= serverkeylen){
+ ksmall = nil;
+ kbig = serverpriv;
+ }else
+ sysfatal("server session and host keys do not differ by at least 128 bits");
+ b := m.getipint();
+ debug(DBG_CRYPTO, sys->sprint("encrypted with kbig is %s\n", b.iptostr(16)));
+ if(kbig != nil)
+ b = sshio->rsadecrypt(kbig, b);
+ else
+# b = rpcdecrypt(rpc, b);
+ b = sshio->rsadecrypt(hostpriv, b);
+ b = sshio->rsaunpad(b);
+ sshio->debug(DBG_CRYPTO, sys->sprint("encrypted with ksmall is %s\n", b.iptostr(16)));
+ if(ksmall != nil)
+ b = sshio->rsadecrypt(ksmall, b);
+ else
+# b = rpcdecrypt(rpc, b);
+ b = sshio->rsadecrypt(hostpriv, b);
+ b = sshio->rsaunpad(b);
+ debug(DBG_CRYPTO, sys->sprint("munged is %s\n", b.iptostr(16)));
+ n := (b.bits()+7)/8;
+ if(n < SESSKEYLEN)
+ sysfatal("client sent short session key");
+ buf := array[SESSKEYLEN] of byte;
+ sshio->iptorjustbe(b, buf, SESSKEYLEN);
+ for(i := 0; i < SESSIDLEN; i++)
+ buf[i] ^= c.sessid[i];
+ c.sesskey[0: ] = buf[0: SESSKEYLEN];
+ debug(DBG_CRYPTO, sys->sprint("unmunged is %.*s\n", SESSKEYLEN*2, sshio->hex(buf)));
+ c.flags = m.get4();
+}
+
+authsrvuser(c: ref Conn)
+{
+ m := recvmsg(c, SSH_CMSG_USER);
+ user := m.getstring();
+ c.user = user;
+ inited := 0;
+ ai: ref Auth->AuthInfo;
+ while(authsrvs != nil && ai == nil){
+# #
+# # * clumsy: if the client aborted the auth_tis early
+# # * we don't send a new failure. we check this by
+# # * looking at c->unget, which is only used in that
+# # * case.
+# #
+ if(c.unget == nil)
+ sendmsg(c, Msg.mk(SSH_SMSG_FAILURE, 0));
+ m = recvmsg(c, -1);
+ for(l := authsrvs; l != nil; l = tl l)
+ if((hd l)->firstmsg() == m.mtype){
+ bit := 1 << (hd l)->id();
+ if((inited & bit) == 0){
+ (hd l)->init(sshio);
+ inited |= bit;
+ }
+ ai = (hd l)->authsrv(c, m);
+ break;
+ }
+ if(l == nil)
+ sshio->badmsg(m, 0, nil);
+ }
+ sendmsg(c, Msg.mk(SSH_SMSG_SUCCESS, 0));
+# if(noworld(ai.cuid))
+# ns := "/lib/namespace.noworld";
+# else
+# ns = nil;
+# if(auth_chuid(ai, ns) < 0){
+# sshlog("auth_chuid to %s: %r", ai.cuid);
+# sysfatal("auth_chuid: %r");
+# }
+# sshlog("logged in as %q", ai.user);
+ if(ai != nil)
+ sys->print("logged in as %q\n", ai.user);
+}
+
+keyjunk()
+{
+ p: array of byte;
+ m: ref IPint;
+ rpc: ref AuthRpc;
+ key: ref PK.RSA;
+
+# #
+# # BUG: should use `attr' to get the key attributes
+# # after the read, but that's not implemented yet.
+# #
+# if((b = Bopen("/mnt/factotum/ctl", OREAD)) == nil)
+# sysfatal("open /mnt/factotum/ctl: %r");
+# while((p = Brdline(b, '\n')) != nil){
+# if(strstr(p, " proto=rsa ") != nil && strstr(p, " service=sshserve ") != nil)
+# break;
+# }
+# if(p == nil)
+# sysfatal("no sshserve keys found in /mnt/factotum/ctl");
+# a = _parseattr(p);
+# Bterm(b);
+# key = rsaprivalloc();
+# if((p = _strfindattr(a, "n")) == nil)
+# sysfatal("no n in sshserve key");
+# if((key.n = IPint.strtoip(p, 16)) == nil)
+# sysfatal("bad n in sshserve key");
+# if((p = _strfindattr(a, "ek")) == nil)
+# sysfatal("no ek in sshserve key");
+# if((key.ek = IPint.strtoip(p, 16)) == nil)
+# sysfatal("bad ek in sshserve key");
+# _freeattr(a);
+# if((afd = sys->open("/mnt/factotum/rpc", ORDWR)) == nil)
+# sysfatal("open /mnt/factotum/rpc: %r");
+# if((rpc = auth_allocrpc(afd)) == nil)
+# sysfatal("auth_allocrpc: %r");
+# p = "proto=rsa role=client service=sshserve";
+# if(auth_rpc(rpc, "start", p, len p) != ARok)
+# sysfatal("auth_rpc start %s: %r", p);
+# if(auth_rpc(rpc, "read", nil, 0) != ARok)
+# sysfatal("auth_rpc read: %r");
+# m = strtomp(rpc.arg, nil, 16, nil);
+# if(mpcmp(m, key.n) != 0)
+# sysfatal("key in /mnt/factotum/ctl does not match rpc key");
+# mpfree(m);
+# c.hostkey = key;
+}
+
+versioning(fd: ref Sys->FD)
+{
+ sys->fprint(fd, "SSH-1.5-Inferno\n");
+ (maj, min, err_or_id) := sshio->readversion(fd);
+ if(maj < 0)
+ sysfatal(err_or_id);
+ if(maj != 1 || min < 5)
+ sysfatal(sys->sprint("protocol mismatch; got %s, need SSH-1.x for x >= 5", err_or_id));
+}
+
+authenticate(c: ref Conn)
+{
+ rpc: ref AuthRpc;
+
+ cookie := array[COOKIELEN] of {* => byte sshio->fastrand()};
+ c.sessid = sshio->calcsessid(c.hostkey.n, serverkey.n, cookie);
+ send_ssh_smsg_public_key(c, cookie);
+ recv_ssh_cmsg_session_key(c, rpc, cookie);
+# afd = nil;
+ c.cipher->init(c.sesskey, 1); # turns on encryption
+ sendmsg(c, Msg.mk(SSH_SMSG_SUCCESS, 0));
+ authsrvuser(c);
+}
+
+startcmd(c: ref Conn, cmd: string): (int, ref Sys->FD, chan of (int, string, string))
+{
+ pfd := array[3] of {* => array[2] of ref Sys->FD};
+ for(i := 0; i < 3; i++)
+ if(sys->pipe(pfd[i]) < 0)
+ sysfatal(sys->sprint("pipe: %r"));
+ wfd := sys->open("#p/"+string sys->pctl(0, nil)+"/wait", Sys->OREAD);
+ if(wfd == nil)
+ sysfatal(sys->sprint("open wait: %r"));
+ pidc := chan of int;
+ spawn startcmd1(c, cmd, pfd, pidc);
+ kidpid := <-pidc;
+ (nil, waited) := wait->monitor(wfd);
+ spawn copyout(c, pfd[1][0], SSH_SMSG_STDOUT_DATA);
+ pfd[1][0] = nil;
+ spawn copyout(c, pfd[2][0], SSH_SMSG_STDERR_DATA);
+ pfd[2][0] = nil;
+ return (kidpid, pfd[0][0], waited);
+}
+
+startcmd1(c: ref Conn, cmd: string, pfd: array of array of ref Sys->FD, pidc: chan of int)
+{
+ sysname := env->getenv("sysname");
+ tz := env->getenv("timezone");
+ sys->pctl(Sys->FORKFD, nil);
+ for(i := 0; i < len pfd; i++)
+ if(sys->dup(pfd[i][1].fd, i) < 0)
+ sysfatal(sys->sprint("dup: %r"));
+ pfd = nil;
+ sys->pctl(Sys->NEWPGRP|Sys->FORKNS|Sys->FORKENV|Sys->NEWFD, 0::1::2::nil);
+ pidc <-= sys->pctl(0, nil);
+ env->setenv("user", c.user);
+ if(sysname != nil)
+ env->setenv("sysname", sysname);
+ if(tz != nil)
+ env->setenv("tz", tz);
+ if(sys->chdir("/usr/"+c.user) < 0)
+ sys->chdir("/");
+ if(cmd != nil){
+ env->setenv("service", "rx");
+ status := sh->run(nil, list of {"/dis/sh.dis", "-lc", cmd});
+ if(status != nil)
+ raise "fail:"+status;
+ }else{
+ env->setenv("service", "con");
+ #execl("/bin/ip/telnetd", "telnetd", "-tn", nil); # TO DO: just for echo and line editing
+ sys->fprint(sys->fildes(2), "sshserve: cannot run /dis/ip/telnetd: %r");
+ }
+}
+
+sysfatal(s: string)
+{
+ sys->print("sysfatal: %s\n", s);
+ notegrp(sys->pctl(0, nil), "zap");
+ exit;
+}
+
+notegrp(pid: int, nil: string)
+{
+ fd := sys->open("#p/"+string pid+"/ctl", Sys->OWRITE);
+ if(fd != nil)
+ sys->fprint(fd, "killgrp");
+}
+
+sendmsg(c: ref Conn, m: ref Msg)
+{
+ c.out <-= m;
+}
diff --git a/appl/cmd/styxlisten.b b/appl/cmd/styxlisten.b
index df136e47..4c8bcc94 100644
--- a/appl/cmd/styxlisten.b
+++ b/appl/cmd/styxlisten.b
@@ -1,6 +1,8 @@
implement Styxlisten;
include "sys.m";
sys: Sys;
+include "dial.m";
+ dial: Dial;
include "draw.m";
include "keyring.m";
keyring: Keyring;
@@ -28,6 +30,9 @@ init(ctxt: ref Draw->Context, argv: list of string)
auth = load Auth Auth->PATH;
if (auth == nil)
badmodule(Auth->PATH);
+ dial = load Dial Dial->PATH;
+ if (dial == nil)
+ badmodule(Dial->PATH);
if ((e := auth->init()) != nil)
error("auth init failed: " + e);
keyring = load Keyring Keyring->PATH;
@@ -76,7 +81,7 @@ init(ctxt: ref Draw->Context, argv: list of string)
arg = nil;
if (doauth && algs == nil)
algs = getalgs();
- addr := netmkaddr(hd argv, "tcp", "styx");
+ addr := dial->netmkaddr(hd argv, "tcp", "styx");
cmd := tl argv;
authinfo: ref Keyring->Authinfo;
@@ -88,8 +93,8 @@ init(ctxt: ref Draw->Context, argv: list of string)
error(sys->sprint("cannot read %s: %r", keyfile));
}
- (ok, c) := sys->announce(addr);
- if (ok == -1)
+ c := dial->announce(addr);
+ if (c == nil)
error(sys->sprint("cannot announce on %s: %r", addr));
if(!trusted){
sys->unmount(nil, "/mnt/keys"); # should do for now
@@ -103,17 +108,17 @@ init(ctxt: ref Draw->Context, argv: list of string)
spawn listener(c, popen(ctxt, cmd, lsync), authinfo, algs, lsync);
}
-listener(c: Sys->Connection, mfd: ref Sys->FD, authinfo: ref Keyring->Authinfo, algs: list of string, lsync: chan of int)
+listener(c: ref Dial->Connection, mfd: ref Sys->FD, authinfo: ref Keyring->Authinfo, algs: list of string, lsync: chan of int)
{
lsync <-= sys->pctl(0, nil);
for (;;) {
- (n, nc) := sys->listen(c);
- if (n == -1)
+ nc := dial->listen(c);
+ if (nc == nil)
error(sys->sprint("listen failed: %r"));
if (verbose)
sys->fprint(stderr(), "styxlisten: got connection from %s",
readfile(nc.dir + "/remote"));
- dfd := sys->open(nc.dir + "/data", Sys->ORDWR);
+ dfd := dial->accept(nc);
if (dfd != nil) {
if(nc.cfd != nil)
sys->fprint(nc.cfd, "keepalive");
@@ -245,18 +250,3 @@ stderr(): ref Sys->FD
{
return sys->fildes(2);
}
-
-netmkaddr(addr, net, svc: string): string
-{
- if(net == nil)
- net = "net";
- (n, nil) := sys->tokenize(addr, "!");
- if(n <= 1){
- if(svc== nil)
- return sys->sprint("%s!%s", net, addr);
- return sys->sprint("%s!%s!%s", net, addr, svc);
- }
- if(svc == nil || n > 2)
- return addr;
- return sys->sprint("%s!%s", addr, svc);
-}
diff --git a/appl/lib/factotum.b b/appl/lib/factotum.b
index 97138fe1..bcf65e6c 100644
--- a/appl/lib/factotum.b
+++ b/appl/lib/factotum.b
@@ -11,6 +11,8 @@ include "sys.m";
include "string.m";
+include "encoding.m";
+
include "factotum.m";
debug := 0;
@@ -183,12 +185,37 @@ rpc(afd: ref Sys->FD, verb: string, a: array of byte): (string, array of byte)
Authinfo.read(fd: ref Sys->FD): ref Authinfo
{
- (o, a) := rpc(fd, "authinfo", nil);
- if(o != "ok")
+ (o, a) := rpc(fd, "authinfo", nil); # deprecated in p9p factotum
+ e := sys->sprint("%r");
+ attrs := rpcattrs(fd);
+ cuid := findattrval(attrs, "cuid");
+ suid := findattrval(attrs, "suid");
+ secret16 := findattrval(attrs, "secret");
+ secret: array of byte;
+ if(secret16 != nil){
+ enc16 := load Encoding Encoding->BASE16PATH;
+ if(enc16 != nil)
+ secret = enc16->dec(secret16);
+ }
+ cap := findattrval(attrs, "cap");
+ if(o != "ok"){
+ if(cuid != nil || suid != nil || secret != nil || cap != nil || attrs != nil)
+ return ref Authinfo(cuid, suid, cap, secret, attrs);
+ sys->werrstr(e);
return nil;
+ }
(n, ai) := Authinfo.unpack(a);
if(n <= 0)
sys->werrstr("bad auth info from factotum");
+ ai.attrs = attrs;
+ if(ai.cuid == nil)
+ ai.cuid = cuid;
+ if(ai.suid == nil)
+ ai.suid = suid;
+ if(ai.cap == nil)
+ ai.cap = cap;
+ if(ai.secret == nil)
+ ai.secret = secret;
return ai;
}
diff --git a/appl/lib/spki/spki.b b/appl/lib/spki/spki.b
index 615aa48e..7a4854df 100644
--- a/appl/lib/spki/spki.b
+++ b/appl/lib/spki/spki.b
@@ -1,7 +1,7 @@
implement SPKI;
#
-# Copyright © 2004 Vita Nuova Holdings Limited
+# Copyright © 2004,2008 Vita Nuova Holdings Limited
#
# To do:
# - diagnostics
@@ -14,11 +14,13 @@ include "sys.m";
include "daytime.m";
daytime: Daytime;
-include "keyring.m";
- kr: Keyring;
- IPint, Certificate, PK, SK: import kr;
+include "ipints.m";
+ ipints: IPints;
+ IPint: import ipints;
-include "security.m";
+include "crypt.m";
+ crypt: Crypt;
+ PK, PKsig, SK: import crypt;
include "bufio.m";
@@ -37,7 +39,7 @@ debug: con 0;
init()
{
sys = load Sys Sys->PATH;
- kr = load Keyring Keyring->PATH;
+ crypt = load Crypt Crypt->PATH;
daytime = load Daytime Daytime->PATH;
sexprs = load Sexprs Sexprs->PATH;
base16 = load Encoding Encoding->BASE16PATH;
@@ -263,23 +265,24 @@ parsesig(e: ref Sexp): ref Signature
sigalg: string;
if(k != nil)
sigalg = k.sigalg();
- return ref Signature(hash, k, sigalg, (nil, val.asdata()) :: nil);
+ return ref Signature(hash, k, sigalg, array[] of {("", val.asdata())});
}
sigalg := val.op();
if(sigalg == nil)
return nil;
- rl: list of (string, array of byte);
+ vals := array[len val.args()] of (string, array of byte);
+ i := 0;
for(els := val.args(); els != nil; els = tl els){
g := hd els;
if(g.islist()){
arg := onlyarg(g);
if(arg == nil)
return nil;
- rl = (g.op(), arg.asdata()) :: rl;
+ vals[i++] = (g.op(), arg.asdata());
}else
- rl = (nil, g.asdata()) :: rl;
+ vals[i++] = ("", g.asdata());
}
- return ref Signature(hash, k, sigalg, revt(rl));
+ return ref Signature(hash, k, sigalg, vals);
}
parsecompound(e: ref Sexp): ref Name
@@ -359,31 +362,30 @@ parsekey(e: ref Sexp): ref Key
kl := (hd l).args();
if(kl == nil)
return nil;
- els: list of (string, ref IPint);
+ els := array[len kl] of (string, array of byte);
+ i := 0;
for(; kl != nil; kl = tl kl){
t := (hd kl).op();
a := onlyarg(hd kl).asdata();
if(a == nil)
return nil;
- ip := IPint.bebytestoip(a);
- if(ip == nil)
- return nil;
- els = (t, ip) :: els;
- }
- krp := ref Keyrep.PK(alg, "sdsi", els);
- (pk, nbits) := krp.mkpk();
- if(pk == nil){
- sys->print("can't convert public-key\n");
- return nil;
+ els[i++] = (t, a);
}
- sk: ref Keyring->SK;
+ pk: ref Crypt->PK;
+ sk: ref Crypt->SK;
+ nbits := 0;
if(issk){
- krp = ref Keyrep.SK(alg, "sdsi", els);
- sk = krp.mksk();
+ (sk, pk, nbits) = mksk(alg, els);
if(sk == nil){
- sys->print("can't convert private-key\n");
+ sys->werrstr("can't convert private-key");
return nil;
}
+ }else{
+ (pk, nbits) = mkpk(alg, els);
+ if(pk == nil){
+ sys->werrstr("can't convert public-key");
+ return nil;
+ }
}
#(ref Key(pk,nil,"md5",nil,nil)).hashed("md5"); # TEST
return ref Key(pk, sk, nbits, mha, enc, nil);
@@ -550,12 +552,12 @@ checksig(c: ref Cert, sig: ref Signature): string
return "missing key for signature";
if(sig.hash == nil)
return "missing hash for signature";
- if(sig.sig == nil)
+ if(sig.params == nil)
return "missing signature value";
pk := sig.key.pk;
if(pk == nil)
- return "missing Keyring->PK for signature"; # TO DO (need a way to tell that key was just a hash)
-#rsacomp((hd sig.sig).t1, sig.key);
+ return "missing Crypt->PK for signature"; # TO DO (need a way to tell that key was just a hash)
+#rsacomp((hd sig.params).t1, sig.key);
#sys->print("nbits= %d\n", sig.key.nbits);
(alg, enc, hashalg) := sig.algs();
if(alg == nil)
@@ -574,10 +576,12 @@ checksig(c: ref Cert, sig: ref Signature): string
#dump("check/hashed", hash);
#dump("check/h", h);
ip := IPint.bebytestoip(h);
- isig := sig2icert(sig, "sdsi", 0);
+ isig := sig2isig(sig);
if(isig == nil)
- return "couldn't convert SPKI signature to Keyring form";
- if(!kr->verifym(pk, isig, ip))
+ return "couldn't convert SPKI signature to Crypt form";
+ if(tagof pk != tagof isig)
+ return "signature and public key are incompatible";
+ if(!crypt->verify(pk, isig, ip))
return "signature does not match";
return nil;
}
@@ -598,7 +602,7 @@ signcert(c: ref Cert, sigalg: string, key: ref Key): (ref Signature, string)
signbytes(data: array of byte, sigalg: string, key: ref Key): (ref Signature, string)
{
if(key.sk == nil)
- return (nil, "missing Keyring->SK for signature");
+ return (nil, "missing private key for signature");
pubkey := ref *key;
pubkey.sk = nil;
sig := ref Signature(nil, pubkey, sigalg, nil); # ref Hash, key, alg, sig: list of (string, array of byte)
@@ -620,18 +624,16 @@ signbytes(data: array of byte, sigalg: string, key: ref Key): (ref Signature, st
#dump("sign/h", h);
sig.hash = ref Hash(hashalg, hash);
ip := IPint.bebytestoip(h);
- icert := kr->signm(key.sk, ip, hashalg);
- if(icert == nil)
- return (nil, "signature failed"); # can't happen?
- (nil, nil, nil, vals) := icert2els(icert);
- if(vals == nil)
- return (nil, "couldn't extract values from Keyring Certificate");
- l: list of (string, array of byte);
- for(; vals != nil; vals = tl vals){
- (n, v) := hd vals;
- l = (f2s("rsa", n), v) :: l;
- }
- sig.sig = revt(l);
+ pick isig := crypt->sign(key.sk, ip) {
+ RSA =>
+ sig.params = array[] of {("", isig.n.iptobebytes())};
+ DSA =>
+ sig.params = array[] of {("r", isig.r.iptobebytes()), ("s", isig.s.iptobebytes())};
+ Elgamal =>
+ sig.params = array[] of {("r", isig.r.iptobebytes()), ("s", isig.s.iptobebytes())};
+ * =>
+ return (nil, "unsupported signature type"); # don't know the elements
+ }
return (sig, nil);
}
@@ -645,11 +647,11 @@ hashbytes(a: array of byte, alg: string): array of byte
hash: array of byte;
case alg {
"md5" =>
- hash = array[Keyring->MD5dlen] of byte;
- kr->md5(a, len a, hash, nil);
+ hash = array[Crypt->MD5dlen] of byte;
+ crypt->md5(a, len a, hash, nil);
"sha" or "sha1" =>
- hash = array[Keyring->SHA1dlen] of byte;
- kr->sha1(a, len a, hash, nil);
+ hash = array[Crypt->SHA1dlen] of byte;
+ crypt->sha1(a, len a, hash, nil);
* =>
raise "Spki->hashbytes: unknown algorithm: "+alg;
}
@@ -701,10 +703,10 @@ sigalgs(alg: string): (string, string, string)
Signature.sexp(sg: self ref Signature): ref Sexp
{
sv: ref Sexp;
- if(len sg.sig != 1){
+ if(len sg.params != 1){
l: list of ref Sexp;
- for(els := sg.sig; els != nil; els = tl els){
- (op, val) := hd els;
+ for(i := 0; i < len sg.params; i++){
+ (op, val) := sg.params[i];
if(op != nil)
l = ref Sexp.List(ref Sexp.String(op,nil) :: ref Sexp.Binary(val,nil) :: nil) :: l;
else
@@ -712,7 +714,7 @@ Signature.sexp(sg: self ref Signature): ref Sexp
}
sv = ref Sexp.List(rev(l));
}else
- sv = ref Sexp.Binary((hd sg.sig).t1, nil); # no list if signature has one component
+ sv = ref Sexp.Binary(sg.params[0].t1, nil); # no list if signature has one component
if(sg.sa != nil)
sv = ref Sexp.List(ref Sexp.String(sg.sa,nil) :: sv :: nil);
return ref Sexp.List(ref Sexp.String("signature",nil) :: sg.hash.sexp() :: sg.key.sexp() ::
@@ -1005,11 +1007,16 @@ Name.eq(a: self ref Name, b: ref Name): int
Key.public(key: self ref Key): ref Key
{
if(key.sk != nil){
- pk := ref *key;
- if(pk.pk == nil)
- pk.pk = kr->sktopk(pk.sk);
- pk.sk = nil;
- return pk;
+ pk := key.pk;
+ if(pk == nil){
+ pk = crypt->sktopk(key.sk);
+ if(pk == nil)
+ return nil;
+ }
+ key = ref *key;
+ key.pk = pk;
+ key.sk = nil;
+ return key;
}
if(key.pk == nil)
return nil;
@@ -1049,9 +1056,9 @@ Key.hashexp(key: self ref Key, alg: string): ref Hash
Key.sigalg(k: self ref Key): string
{
if(k.pk != nil)
- alg := k.pk.sa.name;
+ alg := pkalg(k.pk);
else if(k.sk != nil)
- alg = k.sk.sa.name;
+ alg = skalg(k.sk);
else
return nil;
if(k.halg != nil){
@@ -1062,6 +1069,30 @@ Key.sigalg(k: self ref Key): string
return alg;
}
+skalg(sk: ref SK): string
+{
+ if(sk == nil)
+ return "nil";
+ case tagof sk {
+ tagof SK.RSA => return "rsa";
+ tagof SK.Elgamal => return "elgamal";
+ tagof SK.DSA => return "dsa";
+ * => return "gok";
+ }
+}
+
+pkalg(pk: ref PK): string
+{
+ if(pk == nil)
+ return "nil";
+ case tagof pk {
+ tagof PK.RSA => return "rsa";
+ tagof PK.Elgamal => return "elgamal";
+ tagof PK.DSA => return "dsa";
+ * => return "gok";
+ }
+}
+
Key.text(k: self ref Key): string
{
e := k.sexp();
@@ -1078,24 +1109,19 @@ Key.sexp(k: self ref Key): ref Sexp
return nil;
}
sort := "public-key";
- els: list of (string, ref IPint);
+ els: array of (string, ref IPint);
if(k.sk != nil){
- krp := Keyrep.sk(k.sk);
- if(krp == nil)
- return nil;
- els = krp.els;
+ els = repsk(k.sk);
sort = "private-key";
- }else{
- krp := Keyrep.pk(k.pk);
- if(krp == nil)
- return nil;
- els = krp.els;
- }
+ }else
+ els = reppk(k.pk);
+ if(els == nil)
+ return nil;
rl: list of ref Sexp;
- for(; els != nil; els = tl els){
- (n, v) := hd els;
+ for(i := 0; i < len els; i++){
+ (n, v) := els[i];
a := pre0(v.iptobebytes());
- rl = ref Sexp.List(ref Sexp.String(f2s("rsa", n),nil) :: ref Sexp.Binary(a,nil) :: nil) :: rl;
+ rl = ref Sexp.List(ref Sexp.String(n,nil) :: ref Sexp.Binary(a,nil) :: nil) :: rl;
}
return ref Sexp.List(ref Sexp.String(sort, nil) ::
ref Sexp.List(ref Sexp.String(k.sigalg(),nil) :: rev(rl)) :: nil);
@@ -1115,8 +1141,27 @@ Key.eq(k1: self ref Key, k2: ref Key): int
return 1;
}
}
- if(k1.pk != nil && k2.pk != nil)
- return kr->pktostr(k1.pk) == kr->pktostr(k2.pk); # TO DO
+ if(k1.pk != nil && k2.pk != nil){
+ pick rk1 := k1.pk {
+ RSA =>
+ pick rk2 := k2.pk {
+ RSA =>
+ return rk1.n.eq(rk2.n) && rk1.ek.eq(rk2.n);
+ }
+ DSA =>
+ pick rk2 := k2.pk {
+ DSA =>
+ return rk1.p.eq(rk2.p) && rk1.q.eq(rk2.q) &&
+ rk1.alpha.eq(rk2.alpha) && rk1.key.eq(rk2.key);
+ }
+ Elgamal =>
+ pick rk2 := k2.pk {
+ Elgamal =>
+ return rk1.p.eq(rk2.p) && rk1.alpha.eq(rk2.alpha) &&
+ rk1.key.eq(rk2.key);
+ }
+ }
+ }
return 0;
}
@@ -2032,250 +2077,133 @@ rev[T](l: list of T): list of T
return rl;
}
-revt[S,T](l: list of (S,T)): list of (S,T)
-{
- rl: list of (S,T);
- for(; l != nil; l = tl l)
- rl = hd l :: rl;
- return rl;
-}
-
#
-# the following should probably be in a separate Limbo library module,
-# or provided in some way directly by Keyring
+# these are in the order given in draft-ietf-spki-cert-structure-06.txt
#
-Keyrep: adt {
- alg: string;
- owner: string;
- els: list of (string, ref IPint);
- pick{ # keeps a type distance between public and private keys
- PK =>
- SK =>
- }
-
- pk: fn(pk: ref Keyring->PK): ref Keyrep.PK;
- sk: fn(sk: ref Keyring->SK): ref Keyrep.SK;
- mkpk: fn(k: self ref Keyrep): (ref Keyring->PK, int);
- mksk: fn(k: self ref Keyrep): ref Keyring->SK;
- get: fn(k: self ref Keyrep, n: string): ref IPint;
- getb: fn(k: self ref Keyrep, n: string): array of byte;
- eq: fn(k1: self ref Keyrep, k2: ref Keyrep): int;
-};
-
-#
-# convert an Inferno key into a (name, IPint) representation,
-# where `names' maps between Inferno key component offsets and factotum names
-#
-keyextract(flds: list of string, names: list of (string, int)): list of (string, ref IPint)
+mkpk(alg: string, els: array of (string, array of byte)): (ref Crypt->PK, int)
{
- a := array[len flds] of ref IPint;
- for(i := 0; i < len a; i++){
- a[i] = IPint.b64toip(hd flds);
- flds = tl flds;
- }
- rl: list of (string, ref IPint);
- for(; names != nil; names = tl names){
- (n, p) := hd names;
- if(p < len a)
- rl = (n, a[p]) :: rl;
- }
- return revt(rl);
-}
-
-Keyrep.pk(pk: ref Keyring->PK): ref Keyrep.PK
-{
- s := kr->pktostr(pk);
- (nf, flds) := sys->tokenize(s, "\n");
- if((nf -= 2) < 0)
- return nil;
- case hd flds {
+ case alg {
"rsa" =>
- return ref Keyrep.PK(hd flds, hd tl flds,
- keyextract(tl tl flds, list of {("ek",1), ("n",0)}));
- "elgamal" =>
- return ref Keyrep.PK(hd flds, hd tl flds,
- keyextract(tl tl flds, list of {("p",0), ("alpha",1), ("key",2)}));
+ a := getparams(els, "e" :: "n" :: nil);
+ if(a == nil)
+ break;
+ return (ref PK.RSA(a[1], a[0]), a[1].bits());
"dsa" =>
- return ref Keyrep.PK(hd flds, hd tl flds,
- keyextract(tl tl flds, list of {("p",0), ("alpha",2), ("q",1), ("key",3)}));
- * =>
- return nil;
+ a := getparams(els, "p" :: "g" :: "q" :: "y" :: nil);
+ if(a == nil)
+ break;
+ return (ref PK.DSA(a[0], a[2], a[1], a[3]), a[0].bits());
+ "elgamal" =>
+ a := getparams(els, "p" :: "g" :: "y" :: nil);
+ if(a == nil)
+ break;
+ return (ref PK.Elgamal(a[0], a[1], a[2]), a[0].bits());
}
+ return (nil, 0);
}
-Keyrep.sk(pk: ref Keyring->SK): ref Keyrep.SK
+reppk(pk: ref Crypt->PK): array of (string, ref IPint)
{
- s := kr->sktostr(pk);
- (nf, flds) := sys->tokenize(s, "\n");
- if((nf -= 2) < 0)
- return nil;
- # the ordering of components below should match the one defined in the spki spec
- case hd flds {
- "rsa" =>
- return ref Keyrep.SK(hd flds, hd tl flds,
- keyextract(tl tl flds,list of {("ek",1), ("n",0), ("!dk",2), ("!q",4), ("!p",3), ("!kq",6), ("!kp",5), ("!c2",7)})); # see comment elsewhere about p, q
- "elgamal" =>
- return ref Keyrep.SK(hd flds, hd tl flds,
- keyextract(tl tl flds, list of {("p",0), ("alpha",1), ("key",2), ("!secret",3)}));
- "dsa" =>
- return ref Keyrep.SK(hd flds, hd tl flds,
- keyextract(tl tl flds, list of {("p",0), ("alpha",2), ("q",1), ("key",3), ("!secret",4)}));
+ pick k := pk {
+ RSA =>
+ return array[] of {("e", k.ek), ("n", k.n)};
+ DSA =>
+ return array[] of {("p", k.p), ("g", k.alpha), ("q", k.q), ("y", k.key)};
+ Elgamal =>
+ return array[] of {("p", k.p), ("g", k.alpha), ("y", k.key)};
* =>
return nil;
}
}
-Keyrep.get(k: self ref Keyrep, n: string): ref IPint
-{
- n1 := f2s("rsa", n);
- for(el := k.els; el != nil; el = tl el)
- if((hd el).t0 == n || (hd el).t0 == n1)
- return (hd el).t1;
- return nil;
-}
-
-Keyrep.getb(k: self ref Keyrep, n: string): array of byte
-{
- v := k.get(n);
- if(v == nil)
- return nil;
- return pre0(v.iptobebytes());
-}
-
-Keyrep.mkpk(k: self ref Keyrep): (ref Keyring->PK, int)
+mksk(alg: string, els: array of (string, array of byte)): (ref Crypt->SK, ref Crypt->PK, int)
{
- case k.alg {
+ case alg {
"rsa" =>
- e := k.get("ek");
- n := k.get("n");
- if(e == nil || n == nil)
- return (nil, 0);
- return (kr->strtopk(sys->sprint("rsa\n%s\n%s\n%s\n", k.owner, n.iptob64(), e.iptob64())), n.bits());
- * =>
- raise "Keyrep: unknown algorithm";
+ a := getparams(els, "e" :: "n" :: "d" :: "p" :: "q" :: "a" :: "b" :: "c" :: nil);
+ if(a == nil)
+ break;
+ # NB: p and q (and a and b) roles are reversed between libsec and pkcs
+ pk := ref PK.RSA(a[1], a[0]);
+ sk := ref SK.RSA(pk, a[2], a[4], a[3], a[6], a[5], a[7]);
+ return (sk, pk, a[1].bits());
+ "dsa" =>
+ a := getparams(els, "p" :: "g" :: "q" :: "y" :: "x" :: nil);
+ if(a == nil)
+ break;
+ pk := ref PK.DSA(a[0], a[2], a[1], a[3]);
+ sk := ref SK.DSA(pk, a[4]);
+ return (sk, pk, a[0].bits());
+ "elgamal" =>
+ a := getparams(els, "p" :: "g" :: "y" :: "x" :: nil);
+ if(a == nil)
+ break;
+ pk := ref PK.Elgamal(a[0], a[1], a[2]);
+ sk := ref SK.Elgamal(pk, a[3]);
+ return (sk, pk, a[0].bits());
}
+ return (nil, nil, 0);
}
-Keyrep.mksk(k: self ref Keyrep): ref Keyring->SK
+repsk(sk: ref Crypt->SK): array of (string, ref IPint)
{
- case k.alg {
- "rsa" =>
- e := k.get("ek");
- n := k.get("n");
- dk := k.get("!dk");
- p := k.get("!p");
- q := k.get("!q");
- kp := k.get("!kp");
- kq := k.get("!kq");
- c12 := k.get("!c2");
- if(e == nil || n == nil || dk == nil || p == nil || q == nil || kp == nil || kq == nil || c12 == nil)
- return nil;
- return kr->strtosk(sys->sprint("rsa\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
- k.owner, n.iptob64(), e.iptob64(), dk.iptob64(), p.iptob64(), q.iptob64(),
- kp.iptob64(), kq.iptob64(), c12.iptob64()));
+ pick k := sk {
+ RSA =>
+ return array[] of
+ {("e", k.pk.ek), ("n", k.pk.n), ("d", k.dk), ("p", k.q), ("q", k.p), ("a", k.kq), ("b", k.kp), ("c", k.c2)};
+ DSA =>
+ return array[] of {("p", k.pk.p), ("g", k.pk.alpha), ("q", k.pk.q), ("y", k.pk.key), ("x", k.secret)};
+ Elgamal =>
+ return array[] of {("p", k.pk.p), ("g", k.pk.alpha), ("y", k.pk.key), ("x", k.secret)};
* =>
- raise "Keyrep: unknown algorithm";
- }
-}
-
-#
-# account for naming differences between keyring and factotum, and spki.
-# this might not be the best place for this.
-#
-s2f(s: string): string
-{
- case s {
- "e" => return "ek";
- "d" => return "!dk";
- "p" => return "!q"; # NB: p and q (kp and kq) roles are reversed between libsec and pkcs
- "q" => return "!p";
- "a" => return "!kq";
- "b" => return "!kp";
- "c" => return "!c2";
- * => return s;
+ return nil;
}
}
-f2s(alg: string, s: string): string
+sig2isig(sig: ref Signature): ref Crypt->PKsig
{
- case alg {
+ if(sig.params == nil)
+ return nil;
+ case sig.algs().t0 {
"rsa" =>
- case s {
- "ek" => return "e";
- "!p" => return "q"; # see above
- "!q" => return "p";
- "!dk" => return "d";
- "!kp" => return "b";
- "!kq" => return "a";
- "!c2" => return "c";
- }
+ ip := getp(sig.params, "");
+ if(ip == nil)
+ return nil;
+ return ref PKsig.RSA(ip);
"dsa" =>
- case s {
- "p" or "q" => return s;
- "alpha" => return "g";
- "key" => return "y";
- }
+ a := getparams(sig.params, "r" :: "s" :: nil);
+ if(a == nil)
+ return nil;
+ return ref PKsig.DSA(a[0], a[1]);
+ "elgamal" =>
+ a := getparams(sig.params, "r" :: "s" :: nil);
+ if(a == nil)
+ return nil;
+ return ref PKsig.Elgamal(a[0], a[1]);
* =>
- ;
+ return nil;
}
- if(s != nil && s[0] == '!')
- return s[1:];
- return s;
}
-Keyrep.eq(k1: self ref Keyrep, k2: ref Keyrep): int
+getparams(v: array of (string, array of byte), names: list of string): array of ref IPint
{
- # n⁲ but n is small
- for(l1 := k1.els; l1 != nil; l1 = tl l1){
- (n, v1) := hd l1;
- v2 := k2.get(n);
- if(v2 == nil || !v1.eq(v2))
- return 0;
+ r := array[len names] of ref IPint;
+ for(i := 0; names != nil; names = tl names){
+ r[i] = getp(v, hd names);
+ if(r[i] == nil)
+ return nil;
+ i++;
}
- for(l2 := k2.els; l2 != nil; l2 = tl l2)
- if(k1.get((hd l2).t0) == nil)
- return 0;
- return 1;
+ return r;
}
-sig2icert(sig: ref Signature, signer: string, exp: int): ref Keyring->Certificate
+getp(v: array of (string, array of byte), name: string): ref IPint
{
- if(sig.sig == nil)
- return nil;
- s := sys->sprint("%s\n%s\n%s\n%d\n%s\n", "rsa", sig.hash.alg, signer, exp, base64->enc((hd sig.sig).t1));
-#sys->print("alg %s *** %s\n", sig.sa, base64->enc((hd sig.sig).t1));
- return kr->strtocert(s);
-}
-
-icert2els(cert: ref Keyring->Certificate): (string, string, string, list of (string, array of byte))
-{
- s := kr->certtoattr(cert);
- if(s == nil)
- return (nil, nil, nil, nil);
- (nil, l) := sys->tokenize(s, " "); # really need parseattr, and a better interface
- vals: list of (string, array of byte);
- alg, hashalg, signer: string;
- for(; l != nil; l = tl l){
- (nf, fld) := sys->tokenize(hd l, "=");
- if(nf != 2)
- continue;
- case hd fld {
- "sigalg" =>
- (nf, fld) = sys->tokenize(hd tl fld, "-");
- if(nf != 2)
- continue;
- alg = hd fld;
- hashalg = hd tl fld;
- "signer" =>
- signer = hd tl fld;
- "expires" =>
- ; # don't care
- * =>
- vals = (hd fld, base16->dec(hd tl fld)) :: vals;
- }
- }
- return (alg, hashalg, signer, revt(vals));
+ for(i := 0; i < len v; i++)
+ if(v[i].t0 == name)
+ return IPint.bebytestoip(v[i].t1);
+ return nil;
}
#
@@ -2343,23 +2271,27 @@ pkcs1_encode(ha: string, hash: array of byte, mlen: int): array of byte
#
rsacomp(block: array of byte, akey: ref Key): array of byte
{
- key := Keyrep.pk(akey.pk);
- x := kr->IPint.bebytestoip(block);
- y := x.expmod(key.get("e"), key.get("n"));
- ybytes := y.iptobebytes();
-#dump("rsacomp", ybytes);
- k := 1024; # key.modlen;
- ylen := len ybytes;
- if(ylen < k) {
- a := array[k] of { * => byte 0};
- a[k-ylen:] = ybytes[0:];
- ybytes = a;
- }
- else if(ylen > k) {
- # assume it has leading zeros (mod should make it so)
- a := array[k] of byte;
- a[0:] = ybytes[ylen-k:];
- ybytes = a;
- }
- return ybytes;
+ pick pk := akey.pk {
+ RSA =>
+ x := IPint.bebytestoip(block);
+ y := x.expmod(pk.ek, pk.n);
+ ybytes := y.iptobebytes();
+ #dump("rsacomp", ybytes);
+ k := 1024; # key.modlen;
+ ylen := len ybytes;
+ if(ylen < k) {
+ a := array[k] of { * => byte 0};
+ a[k-ylen:] = ybytes[0:];
+ ybytes = a;
+ }
+ else if(ylen > k) {
+ # assume it has leading zeros (mod should make it so)
+ a := array[k] of byte;
+ a[0:] = ybytes[ylen-k:];
+ ybytes = a;
+ }
+ return ybytes;
+ * =>
+ return nil;
+ }
}
diff --git a/appl/lib/spki/verifier.b b/appl/lib/spki/verifier.b
index ffcdfcad..b2304a10 100644
--- a/appl/lib/spki/verifier.b
+++ b/appl/lib/spki/verifier.b
@@ -7,9 +7,8 @@ implement Verifier;
include "sys.m";
sys: Sys;
-include "keyring.m";
- kr: Keyring;
- IPint: import kr;
+include "ipints.m";
+include "crypt.m";
include "bufio.m";
bufio: Bufio;
@@ -32,7 +31,6 @@ debug := 0;
init()
{
sys = load Sys Sys->PATH;
- kr = load Keyring Keyring->PATH;
bufio = load Bufio Bufio->PATH;
sexprs = load Sexprs Sexprs->PATH;
spki = load SPKI SPKI->PATH;