IdServerIOHandlerTls.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.0 27-03-05 10:04:20 MterWoord
  18. Second import, first time the filenames weren't prefixed with Id
  19. Rev 1.0 27-03-05 09:08:54 MterWoord
  20. Created
  21. }
  22. unit IdServerIOHandlerTls;
  23. interface
  24. uses
  25. IdSSL, IdTlsServerOptions, Mono.Security.Protocol.Tls, IdCarrierStream,
  26. IdSocketStream, System.IO, System.Security.Cryptography, IdGlobal, IdYarn,
  27. System.Security.Cryptography.X509Certificates, Mono.Security.Authenticode,
  28. IdIOHandler, IdSocketHandle, IdThread;
  29. type
  30. TIdServerIOHandlerTls = class(TIdServerIOHandlerSSLBase)
  31. protected
  32. FOptions: TIdTlsServerOptions;
  33. function NewServerSideIOHandlerTls: TIdSSLIOHandlerSocketBase;
  34. procedure InitComponent; override;
  35. public
  36. function MakeFTPSvrPasv: TIdSSLIOHandlerSocketBase; override;
  37. function MakeFTPSvrPort: TIdSSLIOHandlerSocketBase; override;
  38. function MakeClientIOHandler(AYarn: TIdYarn) : TIdIOHandler; override;
  39. function MakeClientIOHandler: TIdSSLIOHandlerSocketBase; override;
  40. function Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler; override;
  41. published
  42. property Options: TIdTlsServerOptions read FOptions write FOptions;
  43. end;
  44. implementation
  45. type
  46. TIdServerSideIOHandlerTls = class(TIdSSLIOHandlerSocketBase)
  47. protected
  48. FOptions: TIdTlsServerOptions;
  49. FTlsServerStream: SslServerStream;
  50. FTlsClientStream: SslClientStream;
  51. FCarrierStream: TIdCarrierStream;
  52. FSocketStream: TIdSocketStream;
  53. FActiveStream: Stream;
  54. FPassThrough: Boolean;
  55. function PrivateKeySelection(certificate: X509Certificate; TargetHost: string): AsymmetricAlgorithm;
  56. function ReadFromSource(ARaiseExceptionIfDisconnected: Boolean; ATimeout: Integer; ARaiseExceptionOnTimeOut: Boolean): Integer; override;
  57. procedure SetPassThrough(const AValue: Boolean); override;
  58. public
  59. procedure CheckForDataOnSource(ATimeOut: Integer); override;
  60. procedure StartSSL; override;
  61. procedure AfterAccept; override;
  62. procedure CheckForDisconnect(ARaiseExceptionIfDisconnected: Boolean; AIgnoreBuffer: Boolean); override;
  63. function Clone: TIdSSLIOHandlerSocketBase; override;
  64. procedure WriteDirect(var ABuffer: TIdBytes); override;
  65. procedure Close; override;
  66. published
  67. property Options: TIdTlsServerOptions read FOptions write FOptions;
  68. end;
  69. { TServerSideIOHandlerTls }
  70. function TIdServerSideIOHandlerTls.Clone: TIdSSLIOHandlerSocketBase;
  71. var
  72. TempResult : TIdServerSideIOHandlerTls;
  73. begin
  74. TempResult := TIdServerSideIOHandlerTls.Create;
  75. TempResult.Options.ClientNeedsCertificate := Options.ClientNeedsCertificate;
  76. TempResult.Options.PrivateKey := Options.PrivateKey;
  77. TempResult.Options.Protocol := Options.Protocol;
  78. TempResult.Options.PublicCertificate := Options.PublicCertificate;
  79. TempResult.IsPeer := IsPeer;
  80. TempResult.PassThrough := PassThrough;
  81. Result := TempResult;
  82. end;
  83. procedure TIdServerSideIOHandlerTls.StartSSL;
  84. begin
  85. inherited;
  86. PassThrough := False;
  87. end;
  88. function TIdServerSideIOHandlerTls.PrivateKeySelection(
  89. certificate: X509Certificate; TargetHost: string): AsymmetricAlgorithm;
  90. begin
  91. Result := FOptions.PrivateKey.RSA;
  92. end;
  93. function TIdServerSideIOHandlerTls.ReadFromSource(
  94. ARaiseExceptionIfDisconnected: Boolean; ATimeout: Integer;
  95. ARaiseExceptionOnTimeOut: Boolean): Integer;
  96. var
  97. TempBuff: array of byte;
  98. TotalBytesRead: Integer;
  99. StartTime: Cardinal;
  100. BytesRead: Integer;
  101. TempBytes: array of byte;
  102. begin
  103. Result := 0;
  104. if FInputBuffer = nil then
  105. Exit;
  106. if FActiveStream <> nil then
  107. begin
  108. SetLength(TempBuff, 512);
  109. TotalBytesRead := 0;
  110. StartTime := Ticks;
  111. repeat
  112. BytesRead := FActiveStream.Read(TempBuff, 0, 512);
  113. if BytesRead <> 0 then
  114. begin
  115. TempBytes := ToBytes(TempBuff, BytesRead);
  116. FInputBuffer.Write(TempBytes);
  117. TotalBytesRead := TotalBytesRead + BytesRead;
  118. end;
  119. if BytesRead <> 512 then
  120. begin
  121. Result := TotalBytesRead;
  122. Exit;
  123. end;
  124. IndySleep(2);
  125. until ( (Abs(GetTickDiff(StartTime, Ticks)) > ATimeOut)
  126. and (not ((ATimeOut = IdTimeoutDefault) or (ATimeOut = IdTimeoutInfinite)))
  127. );
  128. Result := TotalBytesRead;
  129. end;
  130. end;
  131. procedure TIdServerSideIOHandlerTls.CheckForDisconnect(
  132. ARaiseExceptionIfDisconnected, AIgnoreBuffer: Boolean);
  133. begin
  134. try
  135. if FActiveStream = nil then
  136. begin
  137. if AIgnoreBuffer then
  138. begin
  139. CloseGracefully;
  140. end
  141. else
  142. begin
  143. if FInputBuffer.Size = 0 then
  144. begin
  145. CloseGracefully;
  146. end;
  147. end;
  148. end
  149. else
  150. begin
  151. if ( (not FActiveStream.CanRead)
  152. or (not FActiveStream.CanWrite)
  153. ) then
  154. begin
  155. if AIgnoreBuffer then
  156. begin
  157. CloseGracefully;
  158. end
  159. else
  160. begin
  161. if FInputBuffer.Size = 0 then
  162. begin
  163. CloseGracefully;
  164. end;
  165. end;
  166. end;
  167. end;
  168. except
  169. on E: Exception do
  170. begin
  171. CloseGracefully;
  172. end;
  173. end;
  174. if ( (ARaiseExceptionIfDisconnected)
  175. and (ClosedGracefully)
  176. ) then
  177. RaiseConnClosedGracefully;
  178. end;
  179. procedure TIdServerSideIOHandlerTls.CheckForDataOnSource(ATimeOut: Integer);
  180. begin
  181. if Connected then
  182. begin
  183. ReadFromSource(false, ATimeOut, false);
  184. end;
  185. end;
  186. procedure TIdServerSideIOHandlerTls.AfterAccept;
  187. begin
  188. inherited;
  189. FSocketStream := TIdSocketStream.Create(Binding.Handle);
  190. FCarrierStream := TIdCarrierStream.Create(FSocketStream);
  191. FTlsServerStream := SslServerStream.Create(FCarrierStream, FOptions.PublicCertificate, FOptions.ClientNeedsCertificate, true, FOptions.Protocol);
  192. GC.SuppressFinalize(FSocketStream);
  193. GC.SuppressFinalize(FCarrierStream);
  194. GC.SuppressFinalize(FTlsServerStream);
  195. FActiveStream := FCarrierStream;
  196. FTlsServerStream.PrivateKeyCertSelectionDelegate := PrivateKeySelection;
  197. IsPeer := true;
  198. PassThrough := true;
  199. end;
  200. procedure TIdServerSideIOHandlerTls.Close;
  201. begin
  202. if not PassThrough then
  203. begin
  204. if IsPeer then
  205. begin
  206. if FTlsServerStream <> nil then
  207. begin
  208. FTlsServerStream.Close;
  209. FTlsServerStream := nil;
  210. end;
  211. end
  212. else
  213. begin
  214. if FTlsClientStream <> nil then
  215. begin
  216. FTlsClientStream.Close;
  217. FTlsClientStream := nil;
  218. end;
  219. end;
  220. end;
  221. if FCarrierStream <> nil then
  222. begin
  223. FCarrierStream.Close;
  224. FCarrierStream := nil;
  225. end;
  226. if FSocketStream <> nil then
  227. begin
  228. FSocketStream.Close;
  229. FSocketStream := nil;
  230. end;
  231. inherited;
  232. end;
  233. procedure TIdServerSideIOHandlerTls.WriteDirect(var ABuffer: TIdBytes);
  234. begin
  235. if Intercept <> nil then
  236. Intercept.Send(ABuffer);
  237. if FActiveStream <> nil then
  238. begin
  239. FActiveStream.Write(ABuffer, 0, Length(ABuffer));
  240. FActiveStream.Flush;
  241. end
  242. else
  243. raise Exception.Create('No active stream!');
  244. end;
  245. procedure TIdServerSideIOHandlerTls.SetPassThrough(const AValue: Boolean);
  246. var
  247. TempBuff: array[0..0] of byte;
  248. begin
  249. inherited;
  250. if AValue then
  251. begin
  252. if FActiveStream <> nil then
  253. begin
  254. FActiveStream.Close;
  255. FActiveStream := nil;
  256. end;
  257. FActiveStream := FSocketStream;
  258. if IsPeer then
  259. begin
  260. if FTlsServerStream <> nil then
  261. begin
  262. FTlsServerStream.Close;
  263. FTlsServerStream := nil;
  264. end;
  265. FTlsServerStream := SslServerStream.Create(FCarrierStream, FOptions.PublicCertificate, FOptions.ClientNeedsCertificate, true, FOptions.Protocol);
  266. GC.SuppressFinalize(FTlsServerStream);
  267. FTlsServerStream.PrivateKeyCertSelectionDelegate := PrivateKeySelection;
  268. end
  269. else
  270. begin
  271. if FTlsClientStream <> nil then
  272. begin
  273. FTlsClientStream.Close;
  274. FTlsClientStream := nil;
  275. end;
  276. FTlsClientStream := SslClientStream.Create(FCarrierStream, Destination, true, FOptions.Protocol);
  277. GC.SuppressFinalize(FTlsClientStream);
  278. end;
  279. end
  280. else
  281. begin
  282. if IsPeer then
  283. begin
  284. FActiveStream := FTlsServerStream;
  285. end
  286. else
  287. begin
  288. FActiveStream := FTlsClientStream;
  289. end;
  290. FActiveStream.Read(TempBuff, 0, 0);
  291. end;
  292. end;
  293. { TServerIOHandlerTls }
  294. procedure TIdServerIOHandlerTls.InitComponent;
  295. begin
  296. inherited;
  297. FOptions := TIdTlsServerOptions.Create;
  298. end;
  299. function TIdServerIOHandlerTls.NewServerSideIOHandlerTls: TIdSSLIOHandlerSocketBase;
  300. var
  301. TempResult: TIdServerSideIOHandlerTls;
  302. begin
  303. TempResult := TIdServerSideIOHandlerTls.Create;
  304. TempResult.Options := FOptions;
  305. Result := TempResult;
  306. end;
  307. function TIdServerIOHandlerTls.MakeClientIOHandler: TIdSSLIOHandlerSocketBase;
  308. begin
  309. Result := NewServerSideIOHandlerTls;
  310. end;
  311. function TIdServerIOHandlerTls.MakeClientIOHandler(AYarn: TIdYarn): TIdIOHandler;
  312. begin
  313. Result := NewServerSideIOHandlerTls;
  314. end;
  315. function TIdServerIOHandlerTls.MakeFTPSvrPort: TIdSSLIOHandlerSocketBase;
  316. begin
  317. Result := NewServerSideIOHandlerTls;
  318. end;
  319. function TIdServerIOHandlerTls.Accept(ASocket: TIdSocketHandle;
  320. AListenerThread: TIdThread; AYarn: TIdYarn): TIdIOHandler;
  321. var
  322. LIOHandler: TIdServerSideIOHandlerTls;
  323. begin
  324. LIOHandler := TIdServerSideIOHandlerTls.Create;
  325. LIOHandler.Options := FOptions;
  326. LIOHandler.Open;
  327. while not AListenerThread.Stopped do
  328. begin
  329. try
  330. if ASocket.Select(250) then
  331. begin
  332. if LIOHandler.Binding.Accept(ASocket.Handle) then
  333. begin
  334. LIOHandler.AfterAccept;
  335. Result := LIOHandler;
  336. Exit;
  337. end
  338. else
  339. begin
  340. LIOHandler.Close;
  341. Result := nil;
  342. Exit;
  343. end;
  344. end;
  345. finally
  346. if AListenerThread.Stopped then
  347. begin
  348. LIOHandler.Close;
  349. end;
  350. end;
  351. end;
  352. Result := nil;
  353. end;
  354. function TIdServerIOHandlerTls.MakeFTPSvrPasv: TIdSSLIOHandlerSocketBase;
  355. begin
  356. Result := NewServerSideIOHandlerTls;
  357. end;
  358. end.