/source/Delphi/Protocols/IdSSLOpenSSL.pas

# · Pascal · 2217 lines · 1429 code · 252 blank · 536 comment · 142 complexity · daf5dc00277a0b9f381eff2ab2cd4999 MD5 · raw file

Large files are truncated click here to view the full file

  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.39 16/02/2005 23:26:08 CCostelloe
  18. { Changed OnVerifyPeer. Breaks existing implementation of OnVerifyPeer. See
  19. { long comment near top of file.
  20. }
  21. {
  22. { Rev 1.38 1/31/05 6:02:28 PM RLebeau
  23. { Updated _GetThreadId() callback to reflect changes in IdGlobal unit
  24. }
  25. {
  26. { Rev 1.37 7/27/2004 1:54:26 AM JPMugaas
  27. { Now should use the Intercept property for sends.
  28. }
  29. {
  30. { Rev 1.36 2004-05-18 21:38:36 Mattias
  31. { Fixed unload bug
  32. }
  33. {
  34. { Rev 1.35 2004-05-07 16:34:26 Mattias
  35. { Implemented OpenSSL locking callbacks
  36. }
  37. {
  38. { Rev 1.34 27/04/2004 9:38:48 HHariri
  39. { Added compiler directive so it works in BCB
  40. }
  41. {
  42. { Rev 1.33 4/26/2004 12:41:10 AM BGooijen
  43. { Fixed WriteDirect
  44. }
  45. {
  46. { Rev 1.32 2004.04.08 10:55:30 PM czhower
  47. { IOHandler chanegs.
  48. }
  49. {
  50. { Rev 1.31 3/7/2004 9:02:58 PM JPMugaas
  51. { Fixed compiler warning about visibility.
  52. }
  53. {
  54. { Rev 1.30 2004.03.07 11:46:40 AM czhower
  55. { Flushbuffer fix + other minor ones found
  56. }
  57. {
  58. { Rev 1.29 2/7/2004 5:50:50 AM JPMugaas
  59. { Fixed Copyright.
  60. }
  61. {
  62. { Rev 1.28 2/6/2004 3:45:56 PM JPMugaas
  63. { Only a start on NET porting. This is not finished and will not compile on
  64. { DotNET>
  65. }
  66. {
  67. { Rev 1.27 2004.02.03 5:44:24 PM czhower
  68. { Name changes
  69. }
  70. {
  71. { Rev 1.26 1/21/2004 4:03:48 PM JPMugaas
  72. { InitComponent
  73. }
  74. {
  75. { Rev 1.25 1/14/2004 11:39:10 AM JPMugaas
  76. { Server IOHandler now works. Accept was commented out.
  77. }
  78. {
  79. { Rev 1.24 2003.11.29 10:19:28 AM czhower
  80. { Updated for core change to InputBuffer.
  81. }
  82. {
  83. { Rev 1.23 10/21/2003 10:09:14 AM JPMugaas
  84. { Intercept enabled.
  85. }
  86. {
  87. { Rev 1.22 10/21/2003 09:41:38 AM JPMugaas
  88. { Updated for new API. Verified with TIdFTP with active and passive transfers
  89. { as well as clear and protected data channels.
  90. }
  91. {
  92. { Rev 1.21 10/21/2003 07:32:38 AM JPMugaas
  93. { Checked in what I have. Porting still continues.
  94. }
  95. {
  96. Rev 1.20 10/17/2003 1:08:08 AM DSiders
  97. Added localization comments.
  98. }
  99. {
  100. { Rev 1.19 2003.10.12 6:36:44 PM czhower
  101. { Now compiles.
  102. }
  103. {
  104. { Rev 1.18 9/19/2003 11:24:58 AM JPMugaas
  105. { Should compile.
  106. }
  107. {
  108. { Rev 1.17 9/18/2003 10:20:32 AM JPMugaas
  109. { Updated for new API.
  110. }
  111. {
  112. { Rev 1.16 2003.07.16 3:26:52 PM czhower
  113. { Fixed for a core change.
  114. }
  115. {
  116. Rev 1.15 6/30/2003 1:52:22 PM BGooijen
  117. Changed for new buffer interface
  118. }
  119. {
  120. Rev 1.14 6/29/2003 5:42:02 PM BGooijen
  121. fixed probelm in TIdSSLIOHandlerSocketOpenSSL.SetPassThrough that Henrick
  122. Hellström reported
  123. }
  124. {
  125. Rev 1.13 5/7/2003 7:13:00 PM BGooijen
  126. changed Connected to BindingAllocated in ReadFromSource
  127. }
  128. {
  129. Rev 1.12 3/30/2003 12:16:40 AM BGooijen
  130. bugfixed+ added MakeFTPSvrPort/MakeFTPSvrPasv
  131. }
  132. {
  133. { Rev 1.11 3/14/2003 06:56:08 PM JPMugaas
  134. { Added a clone method to the SSLContext.
  135. }
  136. {
  137. { Rev 1.10 3/14/2003 05:29:10 PM JPMugaas
  138. { Change to prevent an AV when shutting down the FTP Server.
  139. }
  140. {
  141. Rev 1.9 3/14/2003 10:00:38 PM BGooijen
  142. Removed TIdServerIOHandlerSSLBase.PeerPassthrough, the ssl is now enabled in
  143. the server-protocol-files
  144. }
  145. {
  146. { Rev 1.8 3/13/2003 11:55:38 AM JPMugaas
  147. { Updated registration framework to give more information.
  148. }
  149. {
  150. { Rev 1.7 3/13/2003 11:07:14 AM JPMugaas
  151. { OpenSSL classes renamed.
  152. }
  153. {
  154. { Rev 1.6 3/13/2003 10:28:16 AM JPMugaas
  155. { Forgot the reegistration - OOPS!!!
  156. }
  157. {
  158. { Rev 1.5 3/13/2003 09:49:42 AM JPMugaas
  159. { Now uses an abstract SSL base class instead of OpenSSL so 3rd-party vendors
  160. { can plug-in their products.
  161. }
  162. {
  163. Rev 1.4 3/13/2003 10:20:08 AM BGooijen
  164. Server side fibers
  165. }
  166. {
  167. { Rev 1.3 2003.02.25 3:56:22 AM czhower
  168. }
  169. {
  170. Rev 1.2 2/5/2003 10:27:46 PM BGooijen
  171. Fixed bug in OpenEncodedConnection
  172. }
  173. {
  174. Rev 1.1 2/4/2003 6:31:22 PM BGooijen
  175. Fixed for Indy 10
  176. }
  177. {
  178. { Rev 1.0 11/13/2002 08:01:24 AM JPMugaas
  179. }
  180. unit IdSSLOpenSSL;
  181. {
  182. Author: Gregor Ibic (gregor.ibic@intelicom.si)
  183. Copyright: (c) Gregor Ibic, Intelicom d.o.o and Indy Working Group.
  184. }
  185. {
  186. Important information concerning OnVerifyPeer:
  187. Rev 1.39 of February 2005 deliberately broke the OnVerifyPeer interface,
  188. which (obviously?) only affects programs that implemented that callback
  189. as part of the SSL negotiation. Note that you really should always
  190. implement OnVerifyPeer, otherwise the certificate of the peer you are
  191. connecting to is NOT checked to ensure it is valid.
  192. Prior to this, if the SSL library detected a problem with a certificate
  193. or the Depth was insufficient (i.e. the "Ok" parameter in VerifyCallback
  194. is 0 / FALSE), then irrespective of whether your OnVerifyPeer returned True
  195. or False, the SSL connection would be deliberately failed.
  196. This created a problem in that even if there was only a very minor
  197. problem with one of the certificates in the chain (OnVerifyPeer is called
  198. once for each certificate in the certificate chain), which the user may
  199. have been happy to accept, the SSL negotiation would be failed. However,
  200. changing the code to allow the SSL connection when a user returned True
  201. for OnVerifyPeer would have meant that existing code which depended on
  202. automatic rejection of invalid certificates would then be accepting
  203. invalid certificates, which would have been an unacceptable security
  204. change.
  205. Consequently, OnVerifyPeer was changed to deliberately break existing code
  206. by adding an AOk parameter. To preserve the previous functionality, your
  207. OnVerifyPeer event should do "Result := AOk;". If you wish to consider
  208. accepting certificates that the SSL library has considered invalid, then
  209. in your OnVerifyPeer, make sure you satisfy yourself that the certificate
  210. really is valid and then set Result to True. In reality, in addition to
  211. checking AOk, you should always implement code that ensures you are only
  212. accepting certificates which are valid (at least from your point of view).
  213. Ciaran Costelloe, ccostelloe@flogas.ie
  214. }
  215. interface
  216. {$TYPEDADDRESS OFF}
  217. {$I IdCompilerDefines.inc}
  218. uses
  219. Classes,
  220. IdGlobal,
  221. IdException,
  222. IdStackConsts,
  223. IdSocketHandle,
  224. {$IFNDEF DOTNET}
  225. IdSSLOpenSSLHeaders,
  226. {$ELSE}
  227. IdSSLOpenSSLHeadersNET,
  228. {$ENDIF}
  229. IdComponent,
  230. IdIOHandler,
  231. IdGlobalProtocols,
  232. IdTCPServer,
  233. IdThread,
  234. IdTCPConnection,
  235. IdIntercept,
  236. IdIOHandlerSocket,
  237. IdSSL,
  238. IdSocks,
  239. IdScheduler,
  240. IdSys,
  241. IdYarn;
  242. type
  243. TIdX509 = class;
  244. TIdSSLVersion = (sslvSSLv2, sslvSSLv23, sslvSSLv3, sslvTLSv1);
  245. TIdSSLMode = (sslmUnassigned, sslmClient, sslmServer, sslmBoth);
  246. TIdSSLVerifyMode = (sslvrfPeer, sslvrfFailIfNoPeerCert, sslvrfClientOnce);
  247. TIdSSLVerifyModeSet = set of TIdSSLVerifyMode;
  248. TIdSSLCtxMode = (sslCtxClient, sslCtxServer);
  249. TIdSSLAction = (sslRead, sslWrite);
  250. TULong = packed record
  251. case Byte of
  252. 0: (B1,B2,B3,B4: Byte);
  253. 1: (W1,W2: Word);
  254. 2: (L1: Longint);
  255. 3: (C1: Cardinal);
  256. end;
  257. TEVP_MD = record
  258. Length: Integer;
  259. MD: Array[0..OPENSSL_EVP_MAX_MD_SIZE-1] of Char;
  260. end;
  261. TByteArray = record
  262. Length: Integer;
  263. Data: PChar;
  264. End;
  265. TIdSSLIOHandlerSocketOpenSSL = class;
  266. TIdSSLCipher = class;
  267. TCallbackEvent = procedure(Msg: String) of object;
  268. TPasswordEvent = procedure(var Password: String) of object;
  269. TVerifyPeerEvent = function(Certificate: TIdX509; AOk: Boolean): Boolean of object;
  270. TIOHandlerNotify = procedure(ASender: TIdSSLIOHandlerSocketOpenSSL) of object;
  271. TIdSSLOptions = class(TPersistent)
  272. protected
  273. fsRootCertFile, fsCertFile, fsKeyFile: String;
  274. fMethod: TIdSSLVersion;
  275. fMode: TIdSSLMode;
  276. fVerifyDepth: Integer;
  277. fVerifyMode: TIdSSLVerifyModeSet;
  278. //fVerifyFile,
  279. fVerifyDirs, fCipherList: String;
  280. procedure AssignTo(ASource: TPersistent); override;
  281. published
  282. property RootCertFile: String read fsRootCertFile write fsRootCertFile;
  283. property CertFile: String read fsCertFile write fsCertFile;
  284. property KeyFile: String read fsKeyFile write fsKeyFile;
  285. property Method: TIdSSLVersion read fMethod write fMethod;
  286. property Mode: TIdSSLMode read fMode write fMode;
  287. property VerifyMode: TIdSSLVerifyModeSet read fVerifyMode write fVerifyMode;
  288. property VerifyDepth: Integer read fVerifyDepth write fVerifyDepth;
  289. // property VerifyFile: String read fVerifyFile write fVerifyFile;
  290. property VerifyDirs: String read fVerifyDirs write fVerifyDirs;
  291. property CipherList: String read fCipherList write fCipherList;
  292. public
  293. // procedure Assign(ASource: TPersistent); override;
  294. end;
  295. TIdSSLContext = class(TObject)
  296. protected
  297. fMethod: TIdSSLVersion;
  298. fMode: TIdSSLMode;
  299. fsRootCertFile, fsCertFile, fsKeyFile: String;
  300. fVerifyDepth: Integer;
  301. fVerifyMode: TIdSSLVerifyModeSet;
  302. // fVerifyFile: String;
  303. fVerifyDirs: String;
  304. fCipherList: String;
  305. fContext: PSSL_CTX;
  306. fStatusInfoOn: Boolean;
  307. // fPasswordRoutineOn: Boolean;
  308. fVerifyOn: Boolean;
  309. fSessionId: Integer;
  310. fCtxMode: TIdSSLCtxMode;
  311. procedure DestroyContext;
  312. function SetSSLMethod: PSSL_METHOD;
  313. procedure SetVerifyMode(Mode: TIdSSLVerifyModeSet; CheckRoutine: Boolean);
  314. function GetVerifyMode: TIdSSLVerifyModeSet;
  315. procedure InitContext(CtxMode: TIdSSLCtxMode);
  316. public
  317. Parent: TObject;
  318. constructor Create;
  319. destructor Destroy; override;
  320. function Clone : TIdSSLContext;
  321. function LoadRootCert: Boolean;
  322. function LoadCert: Boolean;
  323. function LoadKey: Boolean;
  324. property StatusInfoOn: Boolean read fStatusInfoOn write fStatusInfoOn;
  325. // property PasswordRoutineOn: Boolean read fPasswordRoutineOn write fPasswordRoutineOn;
  326. property VerifyOn: Boolean read fVerifyOn write fVerifyOn;
  327. published
  328. property Method: TIdSSLVersion read fMethod write fMethod;
  329. property Mode: TIdSSLMode read fMode write fMode;
  330. property RootCertFile: String read fsRootCertFile write fsRootCertFile;
  331. property CertFile: String read fsCertFile write fsCertFile;
  332. property KeyFile: String read fsKeyFile write fsKeyFile;
  333. // property VerifyMode: TIdSSLVerifyModeSet read GetVerifyMode write SetVerifyMode;
  334. property VerifyMode: TIdSSLVerifyModeSet read fVerifyMode write fVerifyMode;
  335. property VerifyDepth: Integer read fVerifyDepth write fVerifyDepth;
  336. end;
  337. TIdSSLSocket = class(TObject)
  338. private
  339. fPeerCert: TIdX509;
  340. //fCipherList: String;
  341. fSSLCipher: TIdSSLCipher;
  342. fParent: TObject;
  343. fSSLContext: TIdSSLContext;
  344. function GetPeerCert: TIdX509;
  345. function GetSSLError(retCode: Integer): Integer;
  346. function GetSSLCipher: TIdSSLCipher;
  347. public
  348. fSSL: PSSL;
  349. //
  350. constructor Create(Parent: TObject);
  351. procedure Accept(const pHandle: TIdStackSocketHandle; fSSLContext: TIdSSLContext);
  352. procedure Connect(const pHandle: TIdStackSocketHandle; fSSLContext: TIdSSLContext);
  353. function Send(const ABuf : TIdBytes): integer;
  354. function Recv(var ABuf : TIdBytes): integer;
  355. destructor Destroy; override;
  356. function GetSessionID: TByteArray;
  357. function GetSessionIDAsString:String;
  358. procedure SetCipherList(CipherList: String);
  359. //
  360. property PeerCert: TIdX509 read GetPeerCert;
  361. property Cipher: TIdSSLCipher read GetSSLCipher;
  362. end;
  363. TIdSSLIOHandlerSocketOpenSSL = class(TIdSSLIOHandlerSocketBase)
  364. private
  365. fSSLContext: TIdSSLContext;
  366. fxSSLOptions: TIdSSLOptions;
  367. fSSLSocket: TIdSSLSocket;
  368. //fPeerCert: TIdX509;
  369. fOnStatusInfo: TCallbackEvent;
  370. fOnGetPassword: TPasswordEvent;
  371. fOnVerifyPeer: TVerifyPeerEvent;
  372. fSSLLayerClosed: Boolean;
  373. fOnBeforeConnect: TIOHandlerNotify;
  374. // function GetPeerCert: TIdX509;
  375. //procedure CreateSSLContext(axMode: TIdSSLMode);
  376. //
  377. protected
  378. procedure SetPassThrough(const Value: Boolean); override;
  379. procedure DoBeforeConnect(ASender: TIdSSLIOHandlerSocketOpenSSL); virtual;
  380. procedure DoStatusInfo(Msg: String); virtual;
  381. procedure DoGetPassword(var Password: String); virtual;
  382. function DoVerifyPeer(Certificate: TIdX509; AOk: Boolean): Boolean; virtual;
  383. function RecvEnc(var ABuf : TIdBytes): integer; virtual;
  384. function SendEnc(const ABuf : TIdBytes): integer; virtual;
  385. procedure Init;
  386. procedure OpenEncodedConnection; virtual;
  387. //some overrides from base classes
  388. procedure InitComponent; override;
  389. procedure ConnectClient; override;
  390. function ReadFromSource(ARaiseExceptionIfDisconnected: Boolean = True;
  391. ATimeout: Integer = IdTimeoutDefault;
  392. ARaiseExceptionOnTimeout: Boolean = True): Integer; override;
  393. public
  394. procedure WriteDirect(var ABuffer: TIdBytes); override;
  395. destructor Destroy; override;
  396. function Clone : TIdSSLIOHandlerSocketBase; override;
  397. procedure StartSSL; override;
  398. procedure AfterAccept; override;
  399. procedure Close; override;
  400. procedure Open; override;
  401. function Recv(var ABuf : TIdBytes): integer;
  402. function Send(const ABuf : TIdBytes): integer;
  403. property SSLSocket: TIdSSLSocket read fSSLSocket write fSSLSocket;
  404. property PassThrough: Boolean read fPassThrough write SetPassThrough;
  405. property OnBeforeConnect: TIOHandlerNotify read fOnBeforeConnect write fOnBeforeConnect;
  406. property SSLContext: TIdSSLContext read fSSLContext write fSSLContext;
  407. published
  408. property SSLOptions: TIdSSLOptions read fxSSLOptions write fxSSLOptions;
  409. property OnStatusInfo: TCallbackEvent read fOnStatusInfo write fOnStatusInfo;
  410. property OnGetPassword: TPasswordEvent read fOnGetPassword write fOnGetPassword;
  411. property OnVerifyPeer: TVerifyPeerEvent read fOnVerifyPeer write fOnVerifyPeer;
  412. end;
  413. TIdServerIOHandlerSSLOpenSSL = class(TIdServerIOHandlerSSLBase)
  414. private
  415. fSSLContext: TIdSSLContext;
  416. fxSSLOptions: TIdSSLOptions;
  417. // fPeerCert: TIdX509;
  418. // function GetPeerCert: TIdX509;
  419. fIsInitialized: Boolean;
  420. fOnStatusInfo: TCallbackEvent;
  421. fOnGetPassword: TPasswordEvent;
  422. fOnVerifyPeer: TVerifyPeerEvent;
  423. //procedure CreateSSLContext(axMode: TIdSSLMode);
  424. //procedure CreateSSLContext;
  425. protected
  426. procedure DoStatusInfo(Msg: String); virtual;
  427. procedure DoGetPassword(var Password: String); virtual;
  428. function DoVerifyPeer(Certificate: TIdX509; AOk: Boolean): Boolean; virtual;
  429. procedure InitComponent; override;
  430. public
  431. procedure Init; override;
  432. // AListenerThread is a thread and not a yarn. Its the listener thread.
  433. function Accept(
  434. ASocket: TIdSocketHandle;
  435. AListenerThread: TIdThread;
  436. AYarn: TIdYarn
  437. ): TIdIOHandler; override;
  438. // function Accept(ASocket: TIdSocketHandle; AThread: TIdThread) : TIdIOHandler; override;
  439. destructor Destroy; override;
  440. function MakeClientIOHandler : TIdSSLIOHandlerSocketBase; override;
  441. //
  442. function MakeFTPSvrPort : TIdSSLIOHandlerSocketBase; override;
  443. function MakeFTPSvrPasv : TIdSSLIOHandlerSocketBase; override;
  444. //
  445. property SSLContext: TIdSSLContext read fSSLContext;
  446. published
  447. property SSLOptions: TIdSSLOptions read fxSSLOptions write fxSSLOptions;
  448. property OnStatusInfo: TCallbackEvent read fOnStatusInfo write fOnStatusInfo;
  449. property OnGetPassword: TPasswordEvent read fOnGetPassword write fOnGetPassword;
  450. property OnVerifyPeer: TVerifyPeerEvent read fOnVerifyPeer write fOnVerifyPeer;
  451. end;
  452. TIdX509Name = class(TObject)
  453. private
  454. fX509Name: PX509_NAME;
  455. function CertInOneLine: String;
  456. function GetHash: TULong;
  457. function GetHashAsString: String;
  458. public
  459. constructor Create(aX509Name: PX509_NAME);
  460. //
  461. property Hash: TULong read GetHash;
  462. property HashAsString: string read GetHashAsString;
  463. property OneLine: string read CertInOneLine;
  464. end;
  465. TIdX509 = class(TObject)
  466. protected
  467. FX509 : PX509;
  468. FSubject : TIdX509Name;
  469. FIssuer : TIdX509Name;
  470. function RSubject:TIdX509Name;
  471. function RIssuer:TIdX509Name;
  472. function RnotBefore:TDateTime;
  473. function RnotAfter:TDateTime;
  474. function RFingerprint:TEVP_MD;
  475. function RFingerprintAsString:String;
  476. public
  477. Constructor Create(aX509: PX509); virtual;
  478. Destructor Destroy; override;
  479. //
  480. property Fingerprint: TEVP_MD read RFingerprint;
  481. property FingerprintAsString: String read RFingerprintAsString;
  482. property Subject: TIdX509Name read RSubject;
  483. property Issuer: TIdX509Name read RIssuer;
  484. property notBefore: TDateTime read RnotBefore;
  485. property notAfter: TDateTime read RnotAfter;
  486. end;
  487. TIdSSLCipher = class(TObject)
  488. private
  489. FSSLSocket: TIdSSLSocket;
  490. function GetDescription: String;
  491. function GetName: String;
  492. function GetBits: Integer;
  493. function GetVersion: String;
  494. public
  495. constructor Create(AOwner: TIdSSLSocket);
  496. destructor Destroy; override;
  497. published
  498. property Description: String read GetDescription;
  499. property Name: String read GetName;
  500. property Bits: Integer read GetBits;
  501. property Version: String read GetVersion;
  502. end;
  503. type
  504. EIdOpenSSLError = class(EIdException);
  505. EIdOpenSSLLoadError = class(EIdOpenSSLError);
  506. EIdOSSLCouldNotLoadSSLLibrary = class(EIdOpenSSLLoadError);
  507. EIdOSSLModeNotSet = class(EIdOpenSSLError);
  508. EIdOSSLGetMethodError = class(EIdOpenSSLError);
  509. EIdOSSLCreatingContextError = class(EIdOpenSSLError);
  510. EIdOSSLLoadingRootCertError = class(EIdOpenSSLLoadError);
  511. EIdOSSLLoadingCertError = class(EIdOpenSSLLoadError);
  512. EIdOSSLLoadingKeyError = class(EIdOpenSSLLoadError);
  513. EIdOSSLSettingCipherError = class(EIdOpenSSLError);
  514. EIdOSSLDataBindingError = class(EIdOpenSSLError);
  515. EIdOSSLAcceptError = class(EIdOpenSSLError);
  516. EIdOSSLConnectError = class(EIdOpenSSLError);
  517. function LogicalAnd(A, B: Integer): Boolean;
  518. procedure InfoCallback(sslSocket: PSSL; where: Integer; ret: Integer); cdecl;
  519. function PasswordCallback(buf:PChar; size:Integer; rwflag:Integer; userdata: Pointer):Integer; cdecl;
  520. function VerifyCallback(Ok: Integer; ctx: PX509_STORE_CTX):Integer; cdecl;
  521. implementation
  522. uses
  523. IdResourceStringsCore, IdResourceStringsProtocols, IdStack, IdStackBSDBase, IdAntiFreezeBase,
  524. IdExceptionCore, IdResourceStrings,
  525. SyncObjs;
  526. var
  527. DLLLoadCount: Integer = 0;
  528. LockInfoCB: TCriticalSection;
  529. LockPassCB: TCriticalSection;
  530. LockVerifyCB: TCriticalSection;
  531. CallbackLockList: TThreadList;
  532. //////////////////////////////////////////////////////////////
  533. // SSL SUPPORT FUNCTIONS
  534. //////////////////////////////////////////////////////////////
  535. //////////////////////////////////////////////////////////////
  536. // SSL CALLBACK ROUTINES
  537. //////////////////////////////////////////////////////////////
  538. function PasswordCallback(buf:PChar; size:Integer; rwflag:Integer; userdata: Pointer):Integer; cdecl;
  539. var
  540. Password: String;
  541. IdSSLContext: TIdSSLContext;
  542. begin
  543. LockPassCB.Enter;
  544. try
  545. Password := ''; {Do not Localize}
  546. IdSSLContext := TIdSSLContext(userdata);
  547. if (IdSSLContext.Parent is TIdSSLIOHandlerSocketOpenSSL) then begin
  548. TIdSSLIOHandlerSocketOpenSSL(IdSSLContext.Parent).DoGetPassword(Password);
  549. end;
  550. if (IdSSLContext.Parent is TIdServerIOHandlerSSLOpenSSL) then begin
  551. TIdServerIOHandlerSSLOpenSSL(IdSSLContext.Parent).DoGetPassword(Password);
  552. end;
  553. size := Length(Password);
  554. Sys.StrLCopy(buf, PChar(Password + #0), size + 1);
  555. Result := size;
  556. finally
  557. LockPassCB.Leave;
  558. end;
  559. end;
  560. procedure InfoCallback(sslSocket: PSSL; where: Integer; ret: Integer); cdecl;
  561. var
  562. IdSSLSocket: TIdSSLSocket;
  563. StatusStr : String;
  564. begin
  565. LockInfoCB.Enter;
  566. try
  567. IdSSLSocket := TIdSSLSocket(IdSslGetAppData(sslSocket));
  568. StatusStr := Sys.Format(RSOSSLStatusString, [Sys.StrPas(IdSslStateStringLong(sslSocket))]);
  569. if (IdSSLSocket.fParent is TIdSSLIOHandlerSocketOpenSSL) then begin
  570. TIdSSLIOHandlerSocketOpenSSL(IdSSLSocket.fParent).DoStatusInfo(StatusStr);
  571. end;
  572. if (IdSSLSocket.fParent is TIdServerIOHandlerSSLOpenSSL) then begin
  573. TIdServerIOHandlerSSLOpenSSL(IdSSLSocket.fParent).DoStatusInfo(StatusStr);
  574. end;
  575. finally
  576. LockInfoCB.Leave;
  577. end;
  578. end;
  579. {function RSACallback(sslSocket: PSSL; e: Integer; KeyLength: Integer):PRSA; cdecl;
  580. const
  581. RSA: PRSA = nil;
  582. var
  583. SSLSocket: TSSLWSocket;
  584. IdSSLSocket: TIdSSLSocket;
  585. begin
  586. IdSSLSocket := TIdSSLSocket(IdSslGetAppData(sslSocket));
  587. if Assigned(IdSSLSocket) then begin
  588. IdSSLSocket.TriggerSSLRSACallback(KeyLength);
  589. end;
  590. if not Assigned(RSA) then begin
  591. RSA := f_RSA_generate_key(KeyLength, RSA_F4, @RSAProgressCallback, ssl);
  592. end;
  593. Result := RSA;
  594. end;}
  595. function AddMins (const DT: TDateTime; const Mins: Extended): TDateTime;
  596. begin
  597. Result := DT + Mins / (60 * 24)
  598. end;
  599. function AddHrs (const DT: TDateTime; const Hrs: Extended): TDateTime;
  600. begin
  601. Result := DT + Hrs / 24.0
  602. end;
  603. {function GetLocalTZBias: LongInt;
  604. var
  605. TZ : TTimeZoneInformation;
  606. begin
  607. case GetTimeZoneInformation (TZ) of
  608. TIME_ZONE_ID_STANDARD: Result := TZ.Bias + TZ.StandardBias;
  609. TIME_ZONE_ID_DAYLIGHT: Result := TZ.Bias + TZ.DaylightBias;
  610. else
  611. Result := TZ.Bias;
  612. end;
  613. end;}
  614. function GetLocalTime (const DT: TDateTime): TDateTime;
  615. begin
  616. Result := DT - TimeZoneBias{ / (24 * 60)};
  617. end;
  618. procedure SslLockingCallback(mode, n : integer; Afile : PChar; line : integer) cdecl;
  619. var
  620. Lock : TCriticalSection;
  621. begin
  622. with CallbackLockList.LockList do
  623. try
  624. Lock := TCriticalSection(Items[n]);
  625. finally
  626. CallbackLockList.UnlockList;
  627. end;
  628. if (mode and OPENSSL_CRYPTO_LOCK) > 0 then
  629. Lock.Acquire
  630. else
  631. Lock.Release;
  632. end;
  633. procedure PrepareOpenSSLLocking;
  634. var
  635. i, cnt : integer;
  636. begin
  637. with CallbackLockList.LockList do
  638. try
  639. cnt := IdSslCryptoNumLocks;
  640. for i := 0 to cnt-1 do
  641. Add(TCriticalSection.Create);
  642. finally
  643. CallbackLockList.UnlockList;
  644. end;
  645. end;
  646. function _GetThreadID: Integer; cdecl;
  647. begin
  648. // TODO: Verify how well this will work with fibers potentially running from
  649. // thread to thread or many on the same thread.
  650. Result := CurrentThreadId;
  651. end;
  652. function LoadOpenSLLibrary: Boolean;
  653. begin
  654. if not IdSSLOpenSSLHeaders.Load then begin
  655. Result := False;
  656. Exit;
  657. end;
  658. InitializeRandom;
  659. // IdSslRandScreen;
  660. IdSslLoadErrorStrings;
  661. // Successful loading if true
  662. result := IdSslAddSslAlgorithms > 0;
  663. // Create locking structures, we need them for callback routines
  664. // they are probably not thread safe
  665. LockInfoCB := TCriticalSection.Create;
  666. LockPassCB := TCriticalSection.Create;
  667. LockVerifyCB := TCriticalSection.Create;
  668. // Handle internal OpenSSL locking
  669. CallbackLockList := TThreadList.Create;
  670. IdSslSetLockingCallback(SslLockingCallback);
  671. PrepareOpenSSLLocking;
  672. IdSslSetIdCallback(_GetThreadID);
  673. end;
  674. procedure UnLoadOpenSLLibrary;
  675. var
  676. i : integer;
  677. begin
  678. Sys.FreeAndNil(LockInfoCB);
  679. Sys.FreeAndNil(LockPassCB);
  680. Sys.FreeAndNil(LockVerifyCB);
  681. if Assigned(CallbackLockList) then
  682. begin
  683. with CallbackLockList.LockList do
  684. try
  685. for i := 0 to Count-1 do
  686. TObject(Items[i]).Free;
  687. Clear;
  688. finally
  689. CallbackLockList.UnlockList;
  690. end;
  691. Sys.FreeAndNil(CallbackLockList);
  692. end;
  693. IdSSLOpenSSLHeaders.Unload;
  694. end;
  695. function UTCTime2DateTime(UCTTime: PASN1_UTCTIME):TDateTime;
  696. var
  697. year : Word;
  698. month : Word;
  699. day : Word;
  700. hour : Word;
  701. min : Word;
  702. sec : Word;
  703. tz_h : Integer;
  704. tz_m : Integer;
  705. begin
  706. Result := 0;
  707. if IdSslUCTTimeDecode(UCTTime, year, month, day, hour, min, sec, tz_h, tz_m) > 0 Then Begin
  708. Result := Sys.EncodeDate(year, month, day) + Sys.EncodeTime(hour, min, sec, 0);
  709. AddMins(Result, tz_m);
  710. AddHrs(Result, tz_h);
  711. Result := GetLocalTime(Result);
  712. end;
  713. end;
  714. function TranslateInternalVerifyToSLL(Mode: TIdSSLVerifyModeSet): Integer;
  715. begin
  716. Result := OPENSSL_SSL_VERIFY_NONE;
  717. if sslvrfPeer in Mode then Result := Result or OPENSSL_SSL_VERIFY_PEER;
  718. if sslvrfFailIfNoPeerCert in Mode then Result:= Result or OPENSSL_SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  719. if sslvrfClientOnce in Mode then Result:= Result or OPENSSL_SSL_VERIFY_CLIENT_ONCE;
  720. end;
  721. {function TranslateSLLVerifyToInternal(Mode: Integer): TIdSSLVerifyModeSet;
  722. begin
  723. Result := [];
  724. if LogicalAnd(Mode, OPENSSL_SSL_VERIFY_PEER) then Result := Result + [sslvrfPeer];
  725. if LogicalAnd(Mode, OPENSSL_SSL_VERIFY_FAIL_IF_NO_PEER_CERT) then Result := Result + [sslvrfFailIfNoPeerCert];
  726. if LogicalAnd(Mode, OPENSSL_SSL_VERIFY_CLIENT_ONCE) then Result := Result + [sslvrfClientOnce];
  727. end;}
  728. function LogicalAnd(A, B: Integer): Boolean;
  729. begin
  730. Result := (A and B) = B;
  731. end;
  732. function VerifyCallback(Ok: Integer; ctx: PX509_STORE_CTX): Integer; cdecl;
  733. var
  734. hcert: PX509;
  735. Certificate: TIdX509;
  736. hSSL: PSSL;
  737. IdSSLSocket: TIdSSLSocket;
  738. // str: String;
  739. VerifiedOK: Boolean;
  740. Depth: Integer;
  741. // Error: Integer;
  742. LOk: Boolean;
  743. begin
  744. LockVerifyCB.Enter;
  745. try
  746. VerifiedOK := True;
  747. try
  748. hcert := IdSslX509StoreCtxGetCurrentCert(ctx);
  749. hSSL := IdSslX509StoreCtxGetAppData(ctx);
  750. Certificate := TIdX509.Create(hcert);
  751. if hSSL <> nil then begin
  752. IdSSLSocket := TIdSSLSocket(IdSslGetAppData(hSSL));
  753. end
  754. else begin
  755. Result := Ok;
  756. exit;
  757. end;
  758. //Error :=
  759. IdSslX509StoreCtxGetError(ctx);
  760. Depth := IdSslX509StoreCtxGetErrorDepth(ctx);
  761. // str := Format('Certificate: %s', [Certificate.Subject.OneLine]); {Do not Localize}
  762. // str := IdSSLSocket.GetSessionIDAsString;
  763. // ShowMessage(str);
  764. if not ((Ok>0) and (IdSSLSocket.fSSLContext.VerifyDepth>=Depth)) then begin
  765. Ok := 0;
  766. {if Error = OPENSSL_X509_V_OK then begin
  767. Error := OPENSSL_X509_V_ERR_CERT_CHAIN_TOO_LONG;
  768. end;}
  769. end;
  770. LOk := False;
  771. if Ok = 1 then begin
  772. LOk := True;
  773. end;
  774. if (IdSSLSocket.fParent is TIdSSLIOHandlerSocketOpenSSL) then begin
  775. VerifiedOK := TIdSSLIOHandlerSocketOpenSSL(IdSSLSocket.fParent).DoVerifyPeer(Certificate, LOk);
  776. end;
  777. if (IdSSLSocket.fParent is TIdServerIOHandlerSSLOpenSSL) then begin
  778. VerifiedOK := TIdServerIOHandlerSSLOpenSSL(IdSSLSocket.fParent).DoVerifyPeer(Certificate, LOk);
  779. end;
  780. Sys.FreeAndNil(Certificate); // Used to be Certificate.Destroy - any reason for that?
  781. except
  782. end;
  783. //if VerifiedOK and (Ok > 0) then begin
  784. if VerifiedOK {and (Ok > 0)} then begin
  785. Result := 1;
  786. end
  787. else begin
  788. Result := 0;
  789. end;
  790. // Result := Ok; // testing
  791. finally
  792. LockVerifyCB.Leave;
  793. end;
  794. end;
  795. //////////////////////////////////////////////////////
  796. // TIdSSLOptions
  797. ///////////////////////////////////////////////////////
  798. procedure TIdSSLOptions.AssignTo(ASource: TPersistent);
  799. begin
  800. if ASource is TIdSSLOptions then
  801. with TIdSSLOptions(ASource) do begin
  802. RootCertFile := Self.RootCertFile;
  803. CertFile := Self.CertFile;
  804. KeyFile := Self.KeyFile;
  805. Method := Self.Method;
  806. Mode := Self.Mode;
  807. VerifyMode := Self.VerifyMode;
  808. VerifyDepth := Self.VerifyDepth;
  809. VerifyDirs := Self.VerifyDirs;
  810. CipherList := Self.CipherList;
  811. end
  812. else
  813. inherited AssignTo(ASource);
  814. end;
  815. ///////////////////////////////////////////////////////
  816. // TIdServerIOHandlerSSLOpenSSL
  817. ///////////////////////////////////////////////////////
  818. { TIdServerIOHandlerSSLOpenSSL }
  819. procedure TIdServerIOHandlerSSLOpenSSL.InitComponent;
  820. begin
  821. inherited;
  822. fIsInitialized := False;
  823. fxSSLOptions := TIdSSLOptions.Create;
  824. end;
  825. destructor TIdServerIOHandlerSSLOpenSSL.Destroy;
  826. begin
  827. if fSSLContext <> nil then begin
  828. Sys.FreeAndNil(fSSLContext);
  829. end;
  830. Sys.FreeAndNil(fxSSLOptions);
  831. inherited Destroy;
  832. end;
  833. procedure TIdServerIOHandlerSSLOpenSSL.Init;
  834. begin
  835. // CreateSSLContext(SSLOptions.fMode);
  836. // CreateSSLContext;
  837. fSSLContext := TIdSSLContext.Create;
  838. with fSSLContext do begin
  839. Parent := self;
  840. RootCertFile := SSLOptions.RootCertFile;
  841. CertFile := SSLOptions.CertFile;
  842. KeyFile := SSLOptions.KeyFile;
  843. fVerifyDepth := SSLOptions.fVerifyDepth;
  844. fVerifyMode := SSLOptions.fVerifyMode;
  845. // fVerifyFile := SSLOptions.fVerifyFile;
  846. fVerifyDirs := SSLOptions.fVerifyDirs;
  847. fCipherList := SSLOptions.fCipherList;
  848. if Assigned(fOnVerifyPeer) then begin
  849. VerifyOn := True;
  850. end
  851. else begin
  852. VerifyOn := False;
  853. end;
  854. if Assigned(fOnStatusInfo) then begin
  855. StatusInfoOn := True;
  856. end
  857. else begin
  858. StatusInfoOn := False;
  859. end;
  860. { if Assigned(fOnGetPassword) then begin
  861. PasswordRoutineOn := True;
  862. end
  863. else begin
  864. PasswordRoutineOn := False;
  865. end; }
  866. fMethod := SSLOptions.Method;
  867. fMode := SSLOptions.Mode;
  868. fSSLContext.InitContext(sslCtxServer);
  869. end;
  870. fIsInitialized := True;
  871. end;
  872. {function TIdServerIOHandlerSSLOpenSSL.Accept(ASocket: TIdSocketHandle; AThread: TIdThread) : TIdIOHandler; }
  873. function TIdServerIOHandlerSSLOpenSSL.Accept(
  874. ASocket: TIdSocketHandle;
  875. // This is a thread and not a yarn. Its the listener thread.
  876. AListenerThread: TIdThread;
  877. AYarn: TIdYarn
  878. ): TIdIOHandler;
  879. var
  880. tmpIdCIOpenSSL: TIdSSLIOHandlerSocketOpenSSL;
  881. begin
  882. if not fIsInitialized then begin
  883. Init;
  884. end;
  885. tmpIdCIOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  886. tmpIdCIOpenSSL.PassThrough := true;
  887. tmpIdCIOpenSSL.fIsPeer := True;
  888. tmpIdCIOpenSSL.Open;
  889. if tmpIdCIOpenSSL.Binding.Accept(ASocket.Handle) then begin
  890. //we need to pass the SSLOptions for the saocket from the server
  891. tmpIdCIOpenSSL.fxSSLOptions.Free;
  892. tmpIdCIOpenSSL.fxSSLOptions := fxSSLOptions;
  893. tmpIdCIOpenSSL.fSSLSocket := TIdSSLSocket.Create(self);
  894. tmpIdCIOpenSSL.fSSLContext := fSSLContext;
  895. result := tmpIdCIOpenSSL;
  896. end else begin
  897. result := nil;
  898. Sys.FreeAndNil(tmpIdCIOpenSSL);
  899. end;
  900. end;
  901. procedure TIdServerIOHandlerSSLOpenSSL.DoStatusInfo(Msg: String);
  902. begin
  903. if Assigned(fOnStatusInfo) then
  904. fOnStatusInfo(Msg);
  905. end;
  906. procedure TIdServerIOHandlerSSLOpenSSL.DoGetPassword(var Password: String);
  907. begin
  908. if Assigned(fOnGetPassword) then
  909. fOnGetPassword(Password);
  910. end;
  911. function TIdServerIOHandlerSSLOpenSSL.DoVerifyPeer(Certificate: TIdX509; AOk: Boolean): Boolean;
  912. begin
  913. Result := True;
  914. if Assigned(fOnVerifyPeer) then
  915. Result := fOnVerifyPeer(Certificate, AOk);
  916. end;
  917. function TIdServerIOHandlerSSLOpenSSL.MakeFTPSvrPort : TIdSSLIOHandlerSocketBase;
  918. var LIO : TIdSSLIOHandlerSocketOpenSSL;
  919. begin
  920. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  921. LIO.PassThrough := true;
  922. LIO.SSLOptions.Assign(SSLOptions);
  923. LIO.OnGetPassword := OnGetPassword;
  924. LIO.SSLOptions.Mode:= sslmBoth;{doesn't really matter}
  925. LIO.IsPeer:=true;
  926. LIO.SSLContext:= SSLContext;
  927. Result := LIO;
  928. end;
  929. function TIdServerIOHandlerSSLOpenSSL.MakeFTPSvrPasv : TIdSSLIOHandlerSocketBase;
  930. var LIO : TIdSSLIOHandlerSocketOpenSSL;
  931. begin
  932. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  933. LIO.PassThrough := true;
  934. LIO.SSLOptions.Assign(SSLOptions);
  935. LIO.SSLContext := nil;
  936. LIO.OnGetPassword := OnGetPassword;
  937. LIO.SSLOptions.Mode:= sslmBoth;{or sslmServer}
  938. LIO.IsPeer:=true;
  939. Result := LIO;
  940. end;
  941. ///////////////////////////////////////////////////////
  942. // TIdSSLIOHandlerSocketOpenSSL
  943. ///////////////////////////////////////////////////////
  944. function TIdServerIOHandlerSSLOpenSSL.MakeClientIOHandler: TIdSSLIOHandlerSocketBase;
  945. var LIO : TIdSSLIOHandlerSocketOpenSSL;
  946. begin
  947. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  948. LIO.PassThrough := true;
  949. // LIO.SSLOptions.Free;
  950. // LIO.SSLOptions := SSLOptions;
  951. // LIO.SSLContext := SSLContext;
  952. LIO.SSLOptions.Assign(SSLOptions);
  953. // LIO.SSLContext := SSLContext;
  954. LIO.SSLContext := nil;//SSLContext.Clone; // BGO: clone does not work, it must be either NIL, or SSLContext
  955. LIO.OnGetPassword := OnGetPassword;
  956. Result := LIO;
  957. end;
  958. { TIdSSLIOHandlerSocketOpenSSL }
  959. procedure TIdSSLIOHandlerSocketOpenSSL.InitComponent;
  960. begin
  961. inherited;
  962. fIsPeer := False;
  963. fxSSLOptions := TIdSSLOptions.Create;
  964. fSSLLayerClosed := True;
  965. fSSLContext := nil;
  966. end;
  967. destructor TIdSSLIOHandlerSocketOpenSSL.Destroy;
  968. begin
  969. Sys.FreeAndNil(fSSLSocket);
  970. if not fIsPeer then begin
  971. //we do not destroy these in IsPeer equals true
  972. //because these do not belong to us when we are in a server.
  973. Sys.FreeAndNil(fSSLContext);
  974. Sys.FreeAndNil(fxSSLOptions);
  975. end;
  976. inherited Destroy;
  977. end;
  978. procedure TIdSSLIOHandlerSocketOpenSSL.ConnectClient;
  979. begin
  980. inherited ConnectClient;
  981. DoBeforeConnect(self);
  982. // CreateSSLContext(sslmClient);
  983. // CreateSSLContext(SSLOptions.fMode);
  984. StartSSL;
  985. end;
  986. procedure TIdSSLIOHandlerSocketOpenSSL.StartSSL;
  987. begin
  988. try
  989. Init;
  990. except
  991. on EIdOSSLCouldNotLoadSSLLibrary do begin
  992. if not PassThrough then raise;
  993. end;
  994. end;
  995. if not PassThrough then begin
  996. OpenEncodedConnection;
  997. end;
  998. end;
  999. procedure TIdSSLIOHandlerSocketOpenSSL.Close;
  1000. begin
  1001. Sys.FreeAndNil(fSSLSocket);
  1002. if not fIsPeer then begin
  1003. Sys.FreeAndNil(fSSLContext);
  1004. end;
  1005. inherited Close;
  1006. end;
  1007. procedure TIdSSLIOHandlerSocketOpenSSL.Open;
  1008. begin
  1009. inherited Open;
  1010. end;
  1011. function TIdSSLIOHandlerSocketOpenSSL.Recv(var ABuf : TIdBytes): integer;
  1012. begin
  1013. if fPassThrough then begin
  1014. result := Binding.Receive(ABuf);
  1015. // Recv(ABuf, ALen, 0 );
  1016. end
  1017. else begin
  1018. result := RecvEnc(ABuf);
  1019. end;
  1020. end;
  1021. function TIdSSLIOHandlerSocketOpenSSL.Send(const ABuf : TIdBytes): integer;
  1022. begin
  1023. if fPassThrough then begin
  1024. // result := Binding.Send(ABuf, ALen, 0 );
  1025. result := Binding.Send(ABuf,0);
  1026. end
  1027. else begin
  1028. result := SendEnc(ABuf);
  1029. end;
  1030. end;
  1031. procedure TIdSSLIOHandlerSocketOpenSSL.SetPassThrough(const Value: Boolean);
  1032. begin
  1033. if fPassThrough <> Value then begin
  1034. if not Value then begin
  1035. if BindingAllocated then begin
  1036. if Assigned(fSSLContext) then begin
  1037. OpenEncodedConnection;
  1038. end
  1039. else begin
  1040. raise EIdOSSLCouldNotLoadSSLLibrary.Create(RSOSSLCouldNotLoadSSLLibrary);
  1041. end;
  1042. end;
  1043. end;
  1044. fPassThrough := Value;
  1045. end;
  1046. end;
  1047. function TIdSSLIOHandlerSocketOpenSSL.RecvEnc(var ABuf : TIdBytes): integer;
  1048. begin
  1049. Result := fSSLSocket.Recv(ABuf);
  1050. end;
  1051. function TIdSSLIOHandlerSocketOpenSSL.SendEnc(const ABuf : TIdBytes): integer;
  1052. begin
  1053. Result := fSSLSocket.Send(ABuf);
  1054. end;
  1055. procedure TIdSSLIOHandlerSocketOpenSSL.AfterAccept;
  1056. begin
  1057. try
  1058. inherited AfterAccept;
  1059. StartSSL;
  1060. except
  1061. Close;
  1062. raise;
  1063. end;
  1064. end;
  1065. procedure TIdSSLIOHandlerSocketOpenSSL.Init;
  1066. begin
  1067. if not Assigned(fSSLContext) then begin
  1068. fSSLContext := TIdSSLContext.Create;
  1069. with fSSLContext do begin
  1070. Parent := self;
  1071. RootCertFile := SSLOptions.RootCertFile;
  1072. CertFile := SSLOptions.CertFile;
  1073. KeyFile := SSLOptions.KeyFile;
  1074. fVerifyDepth := SSLOptions.fVerifyDepth;
  1075. fVerifyMode := SSLOptions.fVerifyMode;
  1076. // fVerifyFile := SSLOptions.fVerifyFile;
  1077. fVerifyDirs := SSLOptions.fVerifyDirs;
  1078. fCipherList := SSLOptions.fCipherList;
  1079. if Assigned(fOnVerifyPeer) then begin
  1080. VerifyOn := True;
  1081. end
  1082. else begin
  1083. VerifyOn := False;
  1084. end;
  1085. if Assigned(fOnStatusInfo) then begin
  1086. StatusInfoOn := True;
  1087. end
  1088. else begin
  1089. StatusInfoOn := False;
  1090. end;
  1091. {if Assigned(fOnGetPassword) then begin
  1092. PasswordRoutineOn := True;
  1093. end
  1094. else begin
  1095. PasswordRoutineOn := False;
  1096. end;}
  1097. fMethod := SSLOptions.Method;
  1098. fMode := SSLOptions.Mode;
  1099. fSSLContext.InitContext(sslCtxClient);
  1100. end;
  1101. {fSSLContext := TIdSSLContext.Create;
  1102. with fSSLContext do begin
  1103. Parent := self;
  1104. RootCertFile := SSLOptions.RootCertFile;
  1105. CertFile := SSLOptions.CertFile;
  1106. KeyFile := SSLOptions.KeyFile;
  1107. if Assigned(fOnStatusInfo) then begin
  1108. StatusInfoOn := True;
  1109. end
  1110. else begin
  1111. StatusInfoOn := False;
  1112. end;
  1113. if Assigned(fOnVerifyPeer) then begin
  1114. VerifyOn := True;
  1115. end
  1116. else begin
  1117. VerifyOn := False;
  1118. end;
  1119. // Must set mode after above props are set
  1120. Method := SSLOptions.Method;
  1121. Mode := axMode;
  1122. end;}
  1123. end;
  1124. end;
  1125. //}
  1126. {function TIdSSLIOHandlerSocketOpenSSL.GetPeerCert: TIdX509;
  1127. begin
  1128. if fSSLContext <> nil then begin
  1129. Result := fSSLSocket.PeerCert;
  1130. end
  1131. else begin
  1132. Result := nil;
  1133. end;
  1134. end;}
  1135. procedure TIdSSLIOHandlerSocketOpenSSL.DoStatusInfo(Msg: String);
  1136. begin
  1137. if Assigned(fOnStatusInfo) then
  1138. fOnStatusInfo(Msg);
  1139. end;
  1140. procedure TIdSSLIOHandlerSocketOpenSSL.DoGetPassword(var Password: String);
  1141. begin
  1142. if Assigned(fOnGetPassword) then
  1143. fOnGetPassword(Password);
  1144. end;
  1145. function TIdSSLIOHandlerSocketOpenSSL.DoVerifyPeer(Certificate: TIdX509; AOk: Boolean): Boolean;
  1146. begin
  1147. Result := True;
  1148. if Assigned(fOnVerifyPeer) then
  1149. Result := fOnVerifyPeer(Certificate, AOk);
  1150. end;
  1151. procedure TIdSSLIOHandlerSocketOpenSSL.OpenEncodedConnection;
  1152. begin
  1153. if FIsPeer then begin
  1154. if not Assigned(fSSLSocket) then begin
  1155. fSSLSocket := TIdSSLSocket.Create(self);
  1156. fSSLSocket.fSSLContext := fSSLContext;
  1157. end;
  1158. fSSLSocket.Accept(Binding.Handle, fSSLContext);
  1159. end else begin
  1160. if not Assigned(fSSLSocket) then begin
  1161. fSSLSocket := TIdSSLSocket.Create(self);
  1162. fSSLSocket.fSSLContext := fSSLContext;
  1163. fSSLSocket.Connect(Binding.Handle, fSSLContext);
  1164. end;
  1165. end;
  1166. fPassThrough := false;
  1167. end;
  1168. procedure TIdSSLIOHandlerSocketOpenSSL.DoBeforeConnect(ASender: TIdSSLIOHandlerSocketOpenSSL);
  1169. begin
  1170. if Assigned(OnBeforeConnect) then begin
  1171. OnBeforeConnect(Self);
  1172. end;
  1173. end;
  1174. procedure TIdSSLIOHandlerSocketOpenSSL.WriteDirect(var
  1175. ABuffer: TIdBytes
  1176. );
  1177. var
  1178. LBuffer: TIdBytes;
  1179. LBufLen: Integer;
  1180. LCount: Integer;
  1181. LPos: Integer;
  1182. begin
  1183. LPos := 0;
  1184. repeat
  1185. LBufLen := Length(ABuffer) - LPos;
  1186. SetLength(LBuffer,LBufLen);
  1187. Move(ABuffer[LPos],LBuffer[0],LBufLen);
  1188. //we have to make sure we call the Intercept for logging
  1189. if Intercept <> nil then begin
  1190. Intercept.Send(LBuffer);
  1191. end;
  1192. LCount := Send(LBuffer);
  1193. // TODO - Have a AntiFreeze param which allows the send to be split up so that process
  1194. // can be called more. Maybe a prop of the connection, MaxSendSize?
  1195. TIdAntiFreezeBase.DoProcess(False);
  1196. FClosedGracefully := LCount = 0;
  1197. // Check if other side disconnected
  1198. CheckForDisconnect;
  1199. //TODO: This relies on STack - make it abstract
  1200. // Check to see if the error signifies disconnection
  1201. if GBSDStack.CheckForSocketError(LCount, [ID_WSAESHUTDOWN, Id_WSAECONNABORTED
  1202. , Id_WSAECONNRESET]) <> 0 then begin
  1203. FClosedGracefully := True;
  1204. Close;
  1205. GBSDStack.RaiseSocketError(GBSDStack.WSGetLastError);
  1206. end;
  1207. DoWork(wmWrite, LCount);
  1208. LPos := LPos + LCount;
  1209. until LPos >= Length(ABuffer);
  1210. end;
  1211. function TIdSSLIOHandlerSocketOpenSSL.ReadFromSource(
  1212. ARaiseExceptionIfDisconnected: Boolean; ATimeout: Integer;
  1213. ARaiseExceptionOnTimeout: Boolean): Integer;
  1214. // Reads any data in tcp/ip buffer and puts it into Indy buffer
  1215. // This must be the ONLY raw read from Winsock routine
  1216. // This must be the ONLY call to RECV - all data goes thru this method
  1217. var
  1218. LByteCount: Integer;
  1219. LBuffer: TIdBytes;
  1220. LLastError: Integer;
  1221. begin
  1222. if ATimeout = IdTimeoutDefault then begin
  1223. if ReadTimeOut = 0 then begin
  1224. ATimeout := IdTimeoutInfinite;
  1225. end else begin
  1226. ATimeout := FReadTimeout;
  1227. end;
  1228. end;
  1229. Result := 0;
  1230. // Check here as this side may have closed the socket
  1231. CheckForDisconnect(ARaiseExceptionIfDisconnected);
  1232. if BindingAllocated then begin
  1233. LByteCount := 0;
  1234. repeat
  1235. if Readable(ATimeout) then begin
  1236. if Assigned(FRecvBuffer) then begin
  1237. // No need to call AntiFreeze, the Readable does that.
  1238. if BindingAllocated then begin
  1239. SetLength(LBuffer,RecvBufferSize);
  1240. try
  1241. LByteCount := Recv(LBuffer);
  1242. SetLength(LBuffer,LByteCount);
  1243. if Intercept <> nil then begin
  1244. Intercept.Receive(LBuffer);
  1245. LByteCount := Length(LBuffer);
  1246. end;
  1247. FRecvBuffer.Write(LBuffer);
  1248. // WriteBuffer(LBuffer^,LByteCount);
  1249. finally
  1250. SetLength(LBuffer,0);
  1251. end;
  1252. end else begin
  1253. raise EIdClosedSocket.Create(RSStatusDisconnected);
  1254. end;
  1255. end else begin
  1256. LByteCount := 0;
  1257. if ARaiseExceptionIfDisconnected then
  1258. raise EIdException.Create(RSNotConnected);
  1259. end;
  1260. FClosedGracefully := LByteCount = 0;
  1261. if not ClosedGracefully then begin
  1262. LLastError := GBSDStack.CheckForSocketError(LByteCount, [Id_WSAESHUTDOWN
  1263. , Id_WSAECONNABORTED]);
  1264. if LLastError <> 0 then begin
  1265. LByteCount := 0;
  1266. Close;
  1267. // Do not raise unless all data has been read by the user
  1268. if InputBufferIsEmpty then begin
  1269. GBSDStack.RaiseSocketError(LLastError);
  1270. end;
  1271. end;
  1272. // InputBuffer.Size is modified above
  1273. if LByteCount > 0 then begin
  1274. { if Assigned(Intercept) then begin
  1275. IOHandler.RecvBuffer.Position := 0;
  1276. Intercept.Receive(IOHandler.RecvBuffer);
  1277. LByteCount := IOHandler.RecvBuffer.Size;
  1278. end; }
  1279. //AsciiFilter - needs to go in TIdIOHandler
  1280. // if ASCIIFilter then begin
  1281. // for i := 1 to IOHandler.RecvBuffer.Size do begin
  1282. // PChar(IOHandler.RecvBuffer.Memory)[i] := Chr(Ord(PChar(IOHandler.RecvBuffer.Memory)[i]) and $7F);
  1283. // end;
  1284. // end;
  1285. FRecvBuffer.ExtractToIdBuffer(FInputBuffer,-1);
  1286. end;
  1287. end;
  1288. // Check here as other side may have closed connection
  1289. CheckForDisconnect(ARaiseExceptionIfDisconnected);
  1290. Result := LByteCount;
  1291. end else begin
  1292. // Timeout
  1293. if ARaiseExceptionOnTimeout then begin
  1294. raise EIdReadTimeout.Create(RSReadTimeout);
  1295. end;
  1296. Result := -1;
  1297. Break;
  1298. end;
  1299. until (LByteCount <> 0) or (Connected = False);
  1300. end else begin
  1301. if ARaiseExceptionIfDisconnected then begin
  1302. raise EIdException.Create(RSNotConnected);
  1303. end;
  1304. end;
  1305. end;
  1306. function TIdSSLIOHandlerSocketOpenSSL.Clone: TIdSSLIOHandlerSocketBase;
  1307. var LIO : TIdSSLIOHandlerSocketOpenSSL;
  1308. begin
  1309. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  1310. LIO.SSLOptions.Assign( SSLOptions );
  1311. LIO.OnStatusInfo := OnStatusInfo;
  1312. LIO.OnGetPassword := OnGetPassword;
  1313. LIO.OnVerifyPeer := OnVerifyPeer;
  1314. Result := LIO;
  1315. end;
  1316. { TIdSSLContext }
  1317. constructor TIdSSLContext.Create;
  1318. begin
  1319. inherited Create;
  1320. if DLLLoadCount <= 0 then begin
  1321. if not IdSSLOpenSSL.LoadOpenSLLibrary then begin
  1322. raise EIdOSSLCouldNotLoadSSLLibrary.Create(RSOSSLCouldNotLoadSSLLibrary);
  1323. end;
  1324. end;
  1325. Inc(DLLLoadCount);
  1326. fVerifyMode := [];
  1327. fMode := sslmUnassigned;
  1328. fSessionId := 1;
  1329. end;
  1330. destructor TIdSSLContext.Destroy;
  1331. begin
  1332. DestroyContext;
  1333. inherited Destroy;
  1334. end;
  1335. procedure TIdSSLContext.DestroyContext;
  1336. begin
  1337. if fContext <> nil then begin
  1338. IdSslCtxFree(fContext);
  1339. fContext := nil;
  1340. end;
  1341. end;
  1342. procedure TIdSSLContext.InitContext(CtxMode: TIdSSLCtxMode);
  1343. var
  1344. SSLMethod: PSSL_METHOD;
  1345. error: Integer;
  1346. pCipherList, pRootCertFile: PChar;
  1347. // pCAname: PSTACK_X509_NAME;
  1348. begin
  1349. // Destroy the context first
  1350. DestroyContext;
  1351. if fMode = sslmUnassigned then begin
  1352. if CtxMode = sslCtxServer then begin
  1353. fMode := sslmServer;
  1354. end
  1355. else begin
  1356. fMode := sslmClient;
  1357. end
  1358. end;
  1359. // get SSL method function (SSL2, SSL23, SSL3, TLS)
  1360. SSLMethod := SetSSLMethod;
  1361. // create new SSL context
  1362. fContext := IdSslCtxNew(SSLMethod);
  1363. if fContext = nil then begin
  1364. raise EIdOSSLCreatingContextError.Create(RSSSLCreatingContextError);
  1365. end;
  1366. // assign a password lookup routine
  1367. // if PasswordRoutineOn then begin
  1368. IdSslCtxSetDefaultPasswdCb(fContext, @PasswordCallback);
  1369. IdSslCtxSetDefaultPasswdCbUserdata(fContext, self);
  1370. // end;
  1371. IdSSLCtxSetDefaultVerifyPaths(fContext);
  1372. // load key and certificate files
  1373. if RootCertFile <> '' then begin {Do not Localize}
  1374. if not LoadRootCert then begin
  1375. raise EIdOSSLLoadingRootCertError.Create(RSSSLLoadingRootCertError);
  1376. end;
  1377. end;
  1378. if CertFile <> '' then begin {Do not Localize}
  1379. if not LoadCert then begin
  1380. raise EIdOSSLLoadingCertError.Create(RSSSLLoadingCertError);
  1381. end;
  1382. end;
  1383. if KeyFile <> '' then begin {Do not Localize}
  1384. if not LoadKey then begin
  1385. raise EIdOSSLLoadingKeyError.Create(RSSSLLoadingKeyError);
  1386. end;
  1387. end;
  1388. if StatusInfoOn then begin
  1389. IdSslCtxSetInfoCallback(fContext, PFunction(@InfoCallback));
  1390. end;
  1391. // f_SSL_CTX_set_tmp_rsa_callback(hSSLContext, @RSACallback);
  1392. if fCipherList <> '' then begin {Do not Localize}
  1393. pCipherList := Sys.StrNew(PChar(fCipherList));
  1394. error := IdSslCtxSetCipherList(fContext, pCipherList);
  1395. Sys.StrDispose(pCipherList);
  1396. end
  1397. else begin
  1398. error := IdSslCtxSetCipherList(fContext, OPENSSL_SSL_DEFAULT_CIPHER_LIST);
  1399. end;
  1400. if error <= 0 then begin
  1401. raise EIdOSSLSettingCipherError.Create(RSSSLSettingCipherError);
  1402. end;
  1403. if fVerifyMode <> [] then begin
  1404. SetVerifyMode(fVerifyMode, VerifyOn);
  1405. end;
  1406. if CtxMode = sslCtxServer then begin
  1407. IdSSLCtxSetSessionIdContext(fContext, PChar(@fSessionId), SizeOf(fSessionId));
  1408. end;
  1409. // CA list
  1410. if RootCertFile <> '' then begin {Do not Localize}
  1411. pRootCertFile := Sys.StrNew(PChar(RootCertFile));
  1412. IdSSLCtxSetClientCAList(fContext, IdSSLLoadClientCAFile(pRootCertFile));
  1413. Sys.StrDispose(pRootCertFile);
  1414. end
  1415. end;
  1416. procedure TIdSSLContext.SetVerifyMode(Mode: TIdSSLVerifyModeSet; CheckRoutine: Boolean);
  1417. begin
  1418. if fContext<>nil then begin
  1419. // IdSSLCtxSetDefaultVerifyPaths(fContext);
  1420. if CheckRoutine then begin
  1421. IdSslCtxSetVerify(fContext, TranslateInternalVerifyToSLL(Mode), PFunction(@VerifyCallback));
  1422. end
  1423. else begin
  1424. IdSslCtxSetVerify(fContext, TranslateInternalVerifyToSLL(Mode), nil);
  1425. end;
  1426. IdSslCtxSetVerifyDepth(fContext, fVerifyDepth);
  1427. end;
  1428. end;
  1429. function TIdSSLContext.GetVerifyMode: TIdSSLVerifyModeSet;
  1430. begin
  1431. Result := fVerifyMode;
  1432. end;
  1433. {
  1434. function TIdSSLContext.LoadVerifyLocations(FileName: String; Dirs: String): Boolean;
  1435. var
  1436. pFileName, pDirs : PChar;
  1437. begin
  1438. Result := False;
  1439. pFileName := nil;
  1440. pDirs := nil;
  1441. if FileName <> '' then begin
  1442. pFileName := StrNew(PChar(FileName));
  1443. end;
  1444. if Dirs <> '' then begin
  1445. pDirs := StrNew(PChar(Dirs));
  1446. end;
  1447. If (pDirs<>nil) or (pFileName<>nil) Then begin
  1448. If IdSslCtxLoadVerifyLocations(fContext, pFileName, pDirs)<=0 Then Begin
  1449. raise EIdOSSLCouldNotLoadSSLLibrary.Create(RSOSSLCouldNotLoadSSLLibrary);
  1450. exit;
  1451. End;
  1452. end;
  1453. StrDispose(pFileName);
  1454. StrDispose(pDirs);
  1455. Result:=True;
  1456. End;
  1457. }
  1458. function TIdSSLContext.SetSSLMethod: PSSL_METHOD;
  1459. begin
  1460. if fMode = sslmUnassigned then begin
  1461. raise EIdOSSLModeNotSet.create(RSOSSLModeNotSet);
  1462. end;
  1463. case fMethod of
  1464. sslvSSLv2:
  1465. case fMode of
  1466. sslmServer : Result := IdSslMethodServerV2;
  1467. sslmClient : Result := IdSslMethodClientV2;
  1468. sslmBoth : Result := IdSslMethodV2;
  1469. else
  1470. Result := IdSslMethodV2;
  1471. end;
  1472. sslvSSLv23:
  1473. case fMode of
  1474. sslmServer : Result := IdSslMethodServerV23;
  1475. sslmClient : Result := IdSslMethodClientV23;
  1476. sslmBoth : Result := IdSslMethodV23;
  1477. else
  1478. Result := IdSslMethodV23;
  1479. end;
  1480. sslvSSLv3:
  1481. case fMode of
  1482. sslmServer : Result := IdSslMethodServerV3;
  1483. sslmClient : Result := IdSslMethodClientV3;
  1484. sslmBoth : Result := IdSslMethodV3;
  1485. else
  1486. Result := IdSslMethodV3;
  1487. end;
  1488. sslvTLSv1:
  1489. case fMode of
  1490. sslmServer : Result := IdSslMethodServerTLSV1;
  1491. sslmClient : Result := IdSslMethodClientTLSV1;
  1492. sslmBoth : Result := IdSslMethodTLSV1;
  1493. else
  1494. Result := IdSslMethodTLSV1;
  1495. end;
  1496. else
  1497. raise EIdOSSLGetMethodError.Create(RSSSLGetMethodError);
  1498. end;
  1499. end;
  1500. function TIdSSLCont