2 {Challenge-Response Authenticator}
4 USES NetAddr
,ECC
,SHA1
,Chat
,ServerLoop
,MemStream
,opcode
;
13 Callback
:procedure of object;
14 procedure Init(const iRemote
:tNetAddr
);
17 procedure ReplyRes(msg
:tSMsg
; data
:boolean);
18 procedure ReplyPow(msg
:tSMsg
; data
:boolean);
26 procedure tAuth
.Init(const iRemote
:tNetAddr
);
29 Assert(assigned(Callback
) and (not iRemote
.isNil
));
35 Ch
.OnTimeout
:=@Timeout
;
36 Ch
.Callback
:=@ReplyRes
;
37 Ch
.SetTimeout(8001,3000);
38 {generate and send challenge}
40 ECC
.CreateChallenge(challenge
);
41 Ms
.WriteByte(opcode
.crAuthReq
);
43 Ms
.Write(ECC
.PublicKey
,sizeof(PublicKey
));
44 Ms
.Write(challenge
,sizeof(challenge
));
48 procedure tAuth
.ReplyRes(msg
:tSMsg
; data
:boolean);
49 var r
:tMemoryStream
absolute msg
.Stream
;
53 var vresp
:tSha1Digest
;
55 if not data
then exit
;
56 status
:=r
.readbyte
; {todo, set error (eg: unsuported meth)}
57 RPub
:=r
.readptr(sizeof(tEccKey
));
58 resp
:=r
.readptr(sizeof(tEccKey
));
59 ECC
.CreateResponse(Challenge
,vresp
,RPub
^);
60 Valid
:=CompareByte(resp
^,vresp
,sizeof(vresp
))=0;
61 if (status
and 128)=1 then begin
63 Ch
.Callback
:=@ReplyPow
;
67 procedure tAuth
.ReplyPow(msg
:tSMsg
; data
:boolean);
68 var r
:tMemoryStream
absolute msg
.Stream
;
69 var ptp
:byte;{Proof TyPe}
71 var pts
: ^tPoWTimeStamp
;
73 if not data
then exit
;
74 ptp
:=r
.readbyte
; {todo}
75 nonce
:=r
.ReadPtr(sizeof(tEccKey
));
77 PoWValid
:=VerifyPoW(nonce
^,RemotePub
,pts
^);
80 procedure tAuth
.Timeout
;
86 procedure tAuth
.Conclusion
;
91 ms
.WriteByte(byte(Valid
));
92 ms
.WriteByte(byte(PowValid
));
100 FreeMem(@self
,sizeof(self
));
106 procedure SendRep(msg
:tSMsg
; data
:boolean);
107 procedure SendPow(msg
:tSMsg
; data
:boolean);
108 procedure Last(msg
:tSMsg
; data
:boolean);
112 procedure AuthHandler(var ch
:tChat
; msg
:tSMsg
);
115 msg
.stream
.skip(1); {initcode}
118 ch
.OnTimeout
:=@srv
^.Close
;
119 srv
^.SendRep(msg
,true);
126 procedure tServer
.SendRep(msg
:tSMsg
; data
:boolean);
127 var r
:tMemoryStream
absolute msg
.Stream
;
128 var ms
:tMemoryStream
;
131 var resp
:tSha1Digest
;
133 ver
:=r
.ReadByte
; {todo}
134 r
.Read(pub
,sizeof(pub
));
135 chal
:=r
.readptr(sizeof(tEccKey
));
136 CreateResponse(chal
^,resp
,pub
);
137 ch
^.StreamInit(ms
,66); {todo}
139 ms
.Write(PublicKey
,sizeof(PublicKey
));
140 ms
.Write(resp
,sizeof(resp
));
141 ch
^.SetTimeout(8000,0);{no reply expected}
145 procedure tServer
.SendPow(msg
:tSMsg
; data
:boolean);
146 var ms
:tMemoryStream
;
149 ch
^.StreamInit(ms
,66); {todo}
151 ms
.Write(PublicPoW
,sizeof(PublicPoW
));
152 ms
.Write(PublicPoWTS
,2);
153 ch
^.SetTimeout(8000,2000);
157 procedure tServer
.Last(msg
:tSMsg
; data
:boolean);
158 var r
:tMemoryStream
absolute msg
.Stream
;
159 var Valid
,ValidPoW
:byte;
161 if not data
then exit
; {unlikely}
163 ValidPoW
:=r
.ReadByte
;
164 if (Valid
>0)or(ValidPoW
>0) then begin
165 writeln('CRAuth: Our auth failed on remote, reason pub=',Valid
,' pow=',ValidPoW
);
166 Writeln('CRAuth: remote ',string(ch
^.remote
),' ',string(pub
));
170 procedure tServer
.Close
;
173 FreeMem(@self
,sizeof(self
));
176 procedure tAuth
.Cancel
;
183 SetChatHandler(opcode
.crAuthReq
,@AuthHandler
);