Merge 'dev' with dht, ecc auth, proof of work and fixes.
[brdnet.git] / CRAuth.pas
blob66ccd5688118ff596a486c622df44ece36a28f1e
1 unit CRAuth;
2 {Challenge-Response Authenticator}
3 INTERFACE
4 USES NetAddr,ECC,SHA1,Chat,ServerLoop,MemStream,opcode;
5 type
6 tAuth=object
7 ch:tChat;
8 Challenge:tEccKey;
9 RemotePub:tEccKey;
10 Valid:Boolean;
11 PoWValid:Boolean;
12 error:byte;
13 Callback:procedure of object;
14 procedure Init(const iRemote:tNetAddr);
15 procedure Cancel;
16 private
17 procedure ReplyRes(msg:tSMsg; data:boolean);
18 procedure ReplyPow(msg:tSMsg; data:boolean);
19 procedure Done;
20 procedure Timeout;
21 procedure Conclusion;
22 end;
24 IMPLEMENTATION
26 procedure tAuth.Init(const iRemote:tNetAddr);
27 var ms:tMemoryStream;
28 begin
29 Assert(assigned(Callback) and (not iRemote.isNil));
30 Valid:=FALSE;
31 PoWValid:=FALSE;
32 Error:=255;
33 Ch.Init(iRemote);
34 Ch.OnDispose:=@Done;
35 Ch.OnTimeout:=@Timeout;
36 Ch.Callback:=@ReplyRes;
37 Ch.SetTimeout(8001,3000);
38 {generate and send challenge}
39 Ch.StreamInit(ms,66);
40 ECC.CreateChallenge(challenge);
41 Ms.WriteByte(opcode.crAuthReq);
42 Ms.WriteByte(1);
43 Ms.Write(ECC.PublicKey,sizeof(PublicKey));
44 Ms.Write(challenge,sizeof(challenge));
45 Ch.Send(Ms);
46 end;
48 procedure tAuth.ReplyRes(msg:tSMsg; data:boolean);
49 var r:tMemoryStream absolute msg.Stream;
50 var status:byte;
51 var resp:^tEccKey;
52 var vresp:tSha1Digest;
53 begin
54 if not data then exit;
55 status:=r.readbyte; {todo, set error (eg: unsuported meth)}
56 r.Read(RemotePub,sizeof(tEccKey));
57 resp:=r.readptr(sizeof(tEccKey));
58 ECC.CreateResponse(Challenge,vresp,RemotePub);
59 Valid:=CompareByte(resp^,vresp,sizeof(vresp))=0;
60 if (status and 128)>0 then begin
61 {expecting pow}
62 Ch.Callback:=@ReplyPow;
63 Ch.Ack;
64 end else Conclusion;
65 end;
66 procedure tAuth.ReplyPow(msg:tSMsg; data:boolean);
67 var r:tMemoryStream absolute msg.Stream;
68 var ptp:byte;{Proof TyPe}
69 var nonce:^tPoWRec;
70 begin
71 if not data then exit;
72 ptp:=r.readbyte; {todo}
73 nonce:=r.ReadPtr(sizeof(tPoWRec));
74 PoWValid:=VerifyPoW(nonce^,RemotePub);
75 Conclusion;
76 end;
77 procedure tAuth.Timeout;
78 begin
79 error:=251;
80 Callback;
81 Ch.Close;
82 end;
83 procedure tAuth.Conclusion;
84 var ms:tMemoryStream;
85 begin
86 error:=0;
87 Ch.StreamInit(ms,2);
88 ms.WriteByte(byte(Valid));
89 ms.WriteByte(byte(PowValid));
90 Ch.Send(ms);
91 Callback;
92 ch.Close;
93 end;
94 procedure tAuth.Done;
95 begin
96 {called by chat}
97 FreeMem(@self,sizeof(self));
98 end;
100 type tServer=object
101 ch:^tChat;
102 pub:tEccKey;
103 procedure SendRep(msg:tSMsg; data:boolean);
104 procedure SendPow(msg:tSMsg; data:boolean);
105 procedure Last(msg:tSMsg; data:boolean);
106 procedure Close;
107 end;
109 procedure AuthHandler(var ch:tChat; msg:tSMsg);
110 var srv:^tServer;
111 begin
112 msg.stream.skip(1); {initcode}
113 new(srv);
114 srv^.ch:=@ch;
115 ch.OnTimeout:=@srv^.Close;
116 srv^.SendRep(msg,true);
117 {reply with hash}
118 {wait ack}
119 {reply pow}
120 {wait reply}
121 end;
123 procedure tServer.SendRep(msg:tSMsg; data:boolean);
124 var r:tMemoryStream absolute msg.Stream;
125 var ms:tMemoryStream;
126 var ver:byte;
127 var chal:^tEccKey;
128 var resp:tSha1Digest;
129 begin
130 ver:=r.ReadByte; {todo}
131 r.Read(pub,sizeof(pub));
132 chal:=r.readptr(sizeof(tEccKey));
133 CreateResponse(chal^,resp,pub);
134 ch^.StreamInit(ms,66); {todo}
135 ms.WriteByte(128);
136 ms.Write(PublicKey,sizeof(PublicKey));
137 ms.Write(resp,sizeof(resp));
138 ch^.Callback:=@SendPoW;
139 ch^.SetTimeout(8000,0);{no reply expected}
140 ch^.send(ms);
141 end;
143 procedure tServer.SendPow(msg:tSMsg; data:boolean);
144 var ms:tMemoryStream;
145 begin
146 if data then exit;
147 ch^.StreamInit(ms,66); {todo}
148 ms.WriteByte(2);
149 ms.Write(PublicPoW,sizeof(PublicPoW));
150 ch^.Callback:=@Last;
151 ch^.SetTimeout(8000,2000);
152 ch^.send(ms);
153 end;
155 procedure tServer.Last(msg:tSMsg; data:boolean);
156 var r:tMemoryStream absolute msg.Stream;
157 var Valid,ValidPoW:byte;
158 begin
159 if not data then exit; {unlikely}
160 Valid:=r.ReadByte;
161 ValidPoW:=r.ReadByte;
162 if (Valid<>1)or(ValidPoW<>1) then begin
163 write('CRAuth: Our auth failed on remote, reason pub=',Valid,' pow=',ValidPoW);
164 Writeln(' remote ',string(ch^.remote),' ',string(pub));
165 end;
166 Close;
167 end;
168 procedure tServer.Close;
169 begin
170 ch^.Close;
171 FreeMem(@self,sizeof(self));
172 end;
174 procedure tAuth.Cancel;
175 begin
176 error:=247;
177 Ch.Close;
178 end;
180 BEGIN
181 SetChatHandler(opcode.crAuthReq,@AuthHandler);
182 END.