1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
implement Authproto;
# 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
# 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 "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: import authio;
eqbytes, memrandom: import authio;
findattrval: import authio;
init(f: Authio): string
{
authio = f;
sys = load Sys Sys->PATH;
ipints = load IPints IPints->PATH;
crypt = load Crypt Crypt->PATH;
return nil;
}
interaction(attrs: list of ref Attr, io: ref IO): string
{
role := findattrval(attrs, "role");
if(role == nil)
return "role not specified";
if(role != "client")
return "only client role supported";
sk: ref SK.RSA;
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 := crypt->rsadecrypt(sk, 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);
kv(key: ref Key, name: string): ref IPint raises Badkey
{
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(a, 16);
if(m == nil)
raise Badkey("bad value for "+name);
return m;
}
keytorsa(k: ref Key): (ref SK.RSA, string)
{
sk := ref SK.RSA;
sk.pk = ref PK.RSA;
{
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);
}
return (sk, nil);
}
keycheck(k: ref Authio->Key): string
{
return keytorsa(k).t1;
}
|