ssl_cryptlib.pas 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 001.001.002 |
  3. |==============================================================================|
  4. | Content: SSL/SSH support by Peter Gutmann's CryptLib |
  5. |==============================================================================|
  6. | Copyright (c)1999-2015, Lukas Gebauer |
  7. | All rights reserved. |
  8. | |
  9. | Redistribution and use in source and binary forms, with or without |
  10. | modification, are permitted provided that the following conditions are met: |
  11. | |
  12. | Redistributions of source code must retain the above copyright notice, this |
  13. | list of conditions and the following disclaimer. |
  14. | |
  15. | Redistributions in binary form must reproduce the above copyright notice, |
  16. | this list of conditions and the following disclaimer in the documentation |
  17. | and/or other materials provided with the distribution. |
  18. | |
  19. | Neither the name of Lukas Gebauer nor the names of its contributors may |
  20. | be used to endorse or promote products derived from this software without |
  21. | specific prior written permission. |
  22. | |
  23. | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
  24. | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
  25. | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
  26. | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
  27. | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
  28. | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
  29. | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
  30. | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
  31. | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
  32. | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
  33. | DAMAGE. |
  34. |==============================================================================|
  35. | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
  36. | Portions created by Lukas Gebauer are Copyright (c)2005-2015. |
  37. | All Rights Reserved. |
  38. |==============================================================================|
  39. | Contributor(s): |
  40. |==============================================================================|
  41. | History: see HISTORY.HTM from distribution package |
  42. | (Found at URL: http://www.ararat.cz/synapse/) |
  43. |==============================================================================}
  44. {:@abstract(SSL/SSH plugin for CryptLib)
  45. This plugin requires cl32.dll at least version 3.2.0! It can be used on Win32
  46. and Linux. This library is staticly linked - when you compile your application
  47. with this plugin, you MUST distribute it with Cryptib library, otherwise you
  48. cannot run your application!
  49. It can work with keys and certificates stored as PKCS#15 only! It must be stored
  50. as disk file only, you cannot load them from memory! Each file can hold multiple
  51. keys and certificates. You must identify it by 'label' stored in
  52. @link(TSSLCryptLib.PrivateKeyLabel).
  53. If you need to use secure connection and authorize self by certificate
  54. (each SSL/TLS server or client with client authorization), then use
  55. @link(TCustomSSL.PrivateKeyFile), @link(TSSLCryptLib.PrivateKeyLabel) and
  56. @link(TCustomSSL.KeyPassword) properties.
  57. If you need to use server what verifying client certificates, then use
  58. @link(TCustomSSL.CertCAFile) as PKCS#15 file with public keyas of allowed clients. Clients
  59. with non-matching certificates will be rejected by cryptLib.
  60. This plugin is capable to create Ad-Hoc certificates. When you start SSL/TLS
  61. server without explicitly assigned key and certificate, then this plugin create
  62. Ad-Hoc key and certificate for each incomming connection by self. It slowdown
  63. accepting of new connections!
  64. You can use this plugin for SSHv2 connections too! You must explicitly set
  65. @link(TCustomSSL.SSLType) to value LT_SSHv2 and set @link(TCustomSSL.username)
  66. and @link(TCustomSSL.password). You can use special SSH channels too, see
  67. @link(TCustomSSL).
  68. }
  69. {$IFDEF FPC}
  70. {$MODE DELPHI}
  71. {$ENDIF}
  72. {$H+}
  73. {$IFDEF NEXTGEN}
  74. {$ZEROBASEDSTRINGS OFF}
  75. {$ENDIF}
  76. unit ssl_cryptlib;
  77. interface
  78. uses
  79. Windows,
  80. SysUtils,
  81. blcksock, synsock, synautil, synacode,
  82. cryptlib;
  83. type
  84. {:@abstract(class implementing CryptLib SSL/SSH plugin.)
  85. Instance of this class will be created for each @link(TTCPBlockSocket).
  86. You not need to create instance of this class, all is done by Synapse itself!}
  87. TSSLCryptLib = class(TCustomSSL)
  88. protected
  89. FCryptSession: CRYPT_SESSION;
  90. FPrivateKeyLabel: string;
  91. FDelCert: Boolean;
  92. FReadBuffer: string;
  93. FTrustedCAs: array of integer;
  94. function SSLCheck(Value: integer): Boolean;
  95. function Init(server:Boolean): Boolean;
  96. function DeInit: Boolean;
  97. function Prepare(server:Boolean): Boolean;
  98. function GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string;
  99. function CreateSelfSignedCert(Host: string): Boolean; override;
  100. function PopAll: string;
  101. public
  102. {:See @inherited}
  103. constructor Create(const Value: TTCPBlockSocket); override;
  104. destructor Destroy; override;
  105. {:Load trusted CA's in PEM format}
  106. procedure SetCertCAFile(const Value: string); override;
  107. {:See @inherited}
  108. function LibVersion: String; override;
  109. {:See @inherited}
  110. function LibName: String; override;
  111. {:See @inherited}
  112. procedure Assign(const Value: TCustomSSL); override;
  113. {:See @inherited and @link(ssl_cryptlib) for more details.}
  114. function Connect: boolean; override;
  115. {:See @inherited and @link(ssl_cryptlib) for more details.}
  116. function Accept: boolean; override;
  117. {:See @inherited}
  118. function Shutdown: boolean; override;
  119. {:See @inherited}
  120. function BiShutdown: boolean; override;
  121. {:See @inherited}
  122. function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override;
  123. {:See @inherited}
  124. function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override;
  125. {:See @inherited}
  126. function WaitingData: Integer; override;
  127. {:See @inherited}
  128. function GetSSLVersion: string; override;
  129. {:See @inherited}
  130. function GetPeerSubject: string; override;
  131. {:See @inherited}
  132. function GetPeerIssuer: string; override;
  133. {:See @inherited}
  134. function GetPeerName: string; override;
  135. {:See @inherited}
  136. function GetPeerFingerprint: string; override;
  137. {:See @inherited}
  138. function GetVerifyCert: integer; override;
  139. published
  140. {:name of certificate/key within PKCS#15 file. It can hold more then one
  141. certificate/key and each certificate/key must have unique label within one file.}
  142. property PrivateKeyLabel: string read FPrivateKeyLabel Write FPrivateKeyLabel;
  143. end;
  144. implementation
  145. {==============================================================================}
  146. constructor TSSLCryptLib.Create(const Value: TTCPBlockSocket);
  147. begin
  148. inherited Create(Value);
  149. FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
  150. FPrivateKeyLabel := 'synapse';
  151. FDelCert := false;
  152. FTrustedCAs := nil;
  153. end;
  154. destructor TSSLCryptLib.Destroy;
  155. begin
  156. SetCertCAFile(''); // destroy certificates
  157. DeInit;
  158. inherited Destroy;
  159. end;
  160. procedure TSSLCryptLib.Assign(const Value: TCustomSSL);
  161. begin
  162. inherited Assign(Value);
  163. if Value is TSSLCryptLib then
  164. begin
  165. FPrivateKeyLabel := TSSLCryptLib(Value).privatekeyLabel;
  166. end;
  167. end;
  168. function TSSLCryptLib.GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string;
  169. var
  170. l: integer;
  171. begin
  172. l := 0;
  173. cryptGetAttributeString(cryptHandle, attributeType, nil, l);
  174. setlength(Result, l);
  175. cryptGetAttributeString(cryptHandle, attributeType, pointer(Result), l);
  176. setlength(Result, l);
  177. end;
  178. function TSSLCryptLib.LibVersion: String;
  179. var
  180. x: integer;
  181. begin
  182. Result := GetString(CRYPT_UNUSED, CRYPT_OPTION_INFO_DESCRIPTION);
  183. cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_MAJORVERSION, x);
  184. Result := Result + ' v' + IntToStr(x);
  185. cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_MINORVERSION, x);
  186. Result := Result + '.' + IntToStr(x);
  187. cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_STEPPING, x);
  188. Result := Result + '.' + IntToStr(x);
  189. end;
  190. function TSSLCryptLib.LibName: String;
  191. begin
  192. Result := 'ssl_cryptlib';
  193. end;
  194. function TSSLCryptLib.SSLCheck(Value: integer): Boolean;
  195. begin
  196. Result := true;
  197. FLastErrorDesc := '';
  198. if Value = CRYPT_ERROR_COMPLETE then
  199. Value := 0;
  200. FLastError := Value;
  201. if FLastError <> 0 then
  202. begin
  203. Result := False;
  204. {$IF CRYPTLIB_VERSION >= 3400}
  205. FLastErrorDesc := GetString(FCryptSession, CRYPT_ATTRIBUTE_ERRORMESSAGE);
  206. {$ELSE}
  207. FLastErrorDesc := GetString(FCryptSession, CRYPT_ATTRIBUTE_INT_ERRORMESSAGE);
  208. {$IFEND}
  209. end;
  210. end;
  211. function TSSLCryptLib.CreateSelfSignedCert(Host: string): Boolean;
  212. var
  213. privateKey: CRYPT_CONTEXT;
  214. keyset: CRYPT_KEYSET;
  215. cert: CRYPT_CERTIFICATE;
  216. publicKey: CRYPT_CONTEXT;
  217. begin
  218. if FPrivatekeyFile = '' then
  219. FPrivatekeyFile := GetTempFile('', 'key');
  220. cryptCreateContext(privateKey, CRYPT_UNUSED, CRYPT_ALGO_RSA);
  221. cryptSetAttributeString(privateKey, CRYPT_CTXINFO_LABEL, Pointer(FPrivatekeyLabel),
  222. Length(FPrivatekeyLabel));
  223. cryptSetAttribute(privateKey, CRYPT_CTXINFO_KEYSIZE, 1024);
  224. cryptGenerateKey(privateKey);
  225. cryptKeysetOpen(keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, PChar(FPrivatekeyFile), CRYPT_KEYOPT_CREATE);
  226. FDelCert := True;
  227. cryptAddPrivateKey(keyset, privateKey, PChar(FKeyPassword));
  228. cryptCreateCert(cert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTIFICATE);
  229. cryptSetAttribute(cert, CRYPT_CERTINFO_XYZZY, 1);
  230. cryptGetPublicKey(keyset, publicKey, CRYPT_KEYID_NAME, PChar(FPrivatekeyLabel));
  231. cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, publicKey);
  232. cryptSetAttributeString(cert, CRYPT_CERTINFO_COMMONNAME, Pointer(host), Length(host));
  233. cryptSignCert(cert, privateKey);
  234. cryptAddPublicKey(keyset, cert);
  235. cryptKeysetClose(keyset);
  236. cryptDestroyCert(cert);
  237. cryptDestroyContext(privateKey);
  238. cryptDestroyContext(publicKey);
  239. Result := True;
  240. end;
  241. function TSSLCryptLib.PopAll: string;
  242. const
  243. BufferMaxSize = 32768;
  244. var
  245. Outbuffer: string;
  246. WriteLen: integer;
  247. begin
  248. Result := '';
  249. repeat
  250. setlength(outbuffer, BufferMaxSize);
  251. Writelen := 0;
  252. SSLCheck(CryptPopData(FCryptSession, @OutBuffer[1], BufferMaxSize, Writelen));
  253. if FLastError <> 0 then
  254. Break;
  255. if WriteLen > 0 then
  256. begin
  257. setlength(outbuffer, WriteLen);
  258. Result := Result + outbuffer;
  259. end;
  260. until WriteLen = 0;
  261. end;
  262. function TSSLCryptLib.Init(server:Boolean): Boolean;
  263. var
  264. st: CRYPT_SESSION_TYPE;
  265. keysetobj: CRYPT_KEYSET;
  266. cryptContext: CRYPT_CONTEXT;
  267. x: integer;
  268. aUserName : AnsiString;
  269. aPassword: AnsiString;
  270. begin
  271. Result := False;
  272. FLastErrorDesc := '';
  273. FLastError := 0;
  274. FDelCert := false;
  275. FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
  276. if server then
  277. case FSSLType of
  278. LT_all, LT_SSLv3, LT_TLSv1, LT_TLSv1_1, LT_TLSv1_2, LT_TLSv1_3:
  279. st := CRYPT_SESSION_SSL_SERVER;
  280. LT_SSHv2:
  281. st := CRYPT_SESSION_SSH_SERVER;
  282. else
  283. Exit;
  284. end
  285. else
  286. case FSSLType of
  287. LT_all, LT_SSLv3, LT_TLSv1, LT_TLSv1_1, LT_TLSv1_2, LT_TLSv1_3:
  288. st := CRYPT_SESSION_SSL;
  289. LT_SSHv2:
  290. st := CRYPT_SESSION_SSH;
  291. else
  292. Exit;
  293. end;
  294. if not SSLCheck(cryptCreateSession(FcryptSession, CRYPT_UNUSED, st)) then
  295. Exit;
  296. x := -1;
  297. case FSSLType of
  298. LT_SSLv3:
  299. x := 0;
  300. LT_TLSv1:
  301. x := 1;
  302. LT_TLSv1_1:
  303. x := 2;
  304. LT_TLSv1_2:
  305. x := 3;
  306. LT_TLSv1_3:
  307. x := 4;
  308. end;
  309. if x >= 0 then
  310. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_VERSION, x)) then
  311. Exit;
  312. if (FCertComplianceLevel <> -1) then
  313. if not SSLCheck(cryptSetAttribute (CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
  314. FCertComplianceLevel)) then
  315. Exit;
  316. if FUsername <> '' then
  317. begin
  318. aUserName := fUserName;
  319. aPassword := fPassword;
  320. cryptSetAttributeString(FcryptSession, CRYPT_SESSINFO_USERNAME,
  321. Pointer(aUsername), Length(aUsername));
  322. cryptSetAttributeString(FcryptSession, CRYPT_SESSINFO_PASSWORD,
  323. Pointer(aPassword), Length(aPassword));
  324. end;
  325. if FSSLType = LT_SSHv2 then
  326. if FSSHChannelType <> '' then
  327. begin
  328. cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_UNUSED);
  329. cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_TYPE,
  330. Pointer(FSSHChannelType), Length(FSSHChannelType));
  331. if FSSHChannelArg1 <> '' then
  332. cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_ARG1,
  333. Pointer(FSSHChannelArg1), Length(FSSHChannelArg1));
  334. if FSSHChannelArg2 <> '' then
  335. cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_ARG2,
  336. Pointer(FSSHChannelArg2), Length(FSSHChannelArg2));
  337. end;
  338. if server and (FPrivatekeyFile = '') then
  339. begin
  340. if FPrivatekeyLabel = '' then
  341. FPrivatekeyLabel := 'synapse';
  342. if FkeyPassword = '' then
  343. FkeyPassword := 'synapse';
  344. CreateSelfSignedcert(FSocket.ResolveIPToName(FSocket.GetRemoteSinIP));
  345. end;
  346. if (FPrivatekeyLabel <> '') and (FPrivatekeyFile <> '') then
  347. begin
  348. if not SSLCheck(cryptKeysetOpen(KeySetObj, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
  349. PChar(FPrivatekeyFile), CRYPT_KEYOPT_READONLY)) then
  350. Exit;
  351. try
  352. if not SSLCheck(cryptGetPrivateKey(KeySetObj, cryptcontext, CRYPT_KEYID_NAME,
  353. PChar(FPrivatekeyLabel), PChar(FKeyPassword))) then
  354. Exit;
  355. if not SSLCheck(cryptSetAttribute(FcryptSession, CRYPT_SESSINFO_PRIVATEKEY,
  356. cryptcontext)) then
  357. Exit;
  358. finally
  359. cryptKeysetClose(keySetObj);
  360. cryptDestroyContext(cryptcontext);
  361. end;
  362. end;
  363. if server and FVerifyCert then
  364. begin
  365. if not SSLCheck(cryptKeysetOpen(KeySetObj, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
  366. PChar(FCertCAFile), CRYPT_KEYOPT_READONLY)) then
  367. Exit;
  368. try
  369. if not SSLCheck(cryptSetAttribute(FcryptSession, CRYPT_SESSINFO_KEYSET,
  370. keySetObj)) then
  371. Exit;
  372. finally
  373. cryptKeysetClose(keySetObj);
  374. end;
  375. end;
  376. Result := true;
  377. end;
  378. function TSSLCryptLib.DeInit: Boolean;
  379. begin
  380. Result := True;
  381. if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then
  382. CryptDestroySession(FcryptSession);
  383. FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
  384. FSSLEnabled := False;
  385. if FDelCert then
  386. SysUtils.DeleteFile(FPrivatekeyFile);
  387. end;
  388. function TSSLCryptLib.Prepare(server:Boolean): Boolean;
  389. begin
  390. Result := false;
  391. DeInit;
  392. if Init(server) then
  393. Result := true
  394. else
  395. DeInit;
  396. end;
  397. function TSSLCryptLib.Connect: boolean;
  398. begin
  399. Result := False;
  400. if FSocket.Socket = INVALID_SOCKET then
  401. Exit;
  402. if Prepare(false) then
  403. begin
  404. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_NETWORKSOCKET, FSocket.Socket)) then
  405. Exit;
  406. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 1)) then
  407. Exit;
  408. if FverifyCert then
  409. if (GetVerifyCert <> 0) or (not DoVerifyCert) then
  410. Exit;
  411. FSSLEnabled := True;
  412. Result := True;
  413. FReadBuffer := '';
  414. end;
  415. end;
  416. function TSSLCryptLib.Accept: boolean;
  417. begin
  418. Result := False;
  419. if FSocket.Socket = INVALID_SOCKET then
  420. Exit;
  421. if Prepare(true) then
  422. begin
  423. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_NETWORKSOCKET, FSocket.Socket)) then
  424. Exit;
  425. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 1)) then
  426. Exit;
  427. FSSLEnabled := True;
  428. Result := True;
  429. FReadBuffer := '';
  430. end;
  431. end;
  432. function TSSLCryptLib.Shutdown: boolean;
  433. begin
  434. Result := BiShutdown;
  435. end;
  436. function TSSLCryptLib.BiShutdown: boolean;
  437. begin
  438. if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then
  439. cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 0);
  440. DeInit;
  441. FReadBuffer := '';
  442. Result := True;
  443. end;
  444. function TSSLCryptLib.SendBuffer(Buffer: TMemory; Len: Integer): Integer;
  445. var
  446. l: integer;
  447. begin
  448. FLastError := 0;
  449. FLastErrorDesc := '';
  450. SSLCheck(cryptPushData(FCryptSession, Buffer, Len, L));
  451. cryptFlushData(FcryptSession);
  452. Result := l;
  453. end;
  454. function TSSLCryptLib.RecvBuffer(Buffer: TMemory; Len: Integer): Integer;
  455. begin
  456. FLastError := 0;
  457. FLastErrorDesc := '';
  458. if Length(FReadBuffer) = 0 then
  459. FReadBuffer := PopAll;
  460. if Len > Length(FReadBuffer) then
  461. Len := Length(FReadBuffer);
  462. Move(Pointer(FReadBuffer)^, buffer^, Len);
  463. Delete(FReadBuffer, 1, Len);
  464. Result := Len;
  465. end;
  466. function TSSLCryptLib.WaitingData: Integer;
  467. begin
  468. Result := Length(FReadBuffer);
  469. end;
  470. function TSSLCryptLib.GetSSLVersion: string;
  471. var
  472. x: integer;
  473. begin
  474. Result := '';
  475. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  476. Exit;
  477. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_VERSION, x);
  478. if FSSLType in [LT_SSLv3, LT_TLSv1, LT_TLSv1_1, LT_TLSv1_2, LT_TLSv1_3, LT_all] then
  479. case x of
  480. 0:
  481. Result := 'SSLv3';
  482. 1:
  483. Result := 'TLSv1';
  484. 2:
  485. Result := 'TLSv1.1';
  486. 3:
  487. Result := 'TLSv1.2';
  488. 4:
  489. Result := 'TLSv1.3';
  490. end;
  491. if FSSLType in [LT_SSHv2] then
  492. case x of
  493. 0:
  494. Result := 'SSHv1';
  495. 1:
  496. Result := 'SSHv2';
  497. end;
  498. end;
  499. function TSSLCryptLib.GetPeerSubject: string;
  500. var
  501. cert: CRYPT_CERTIFICATE;
  502. begin
  503. Result := '';
  504. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  505. Exit;
  506. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  507. cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME);
  508. Result := GetString(cert, CRYPT_CERTINFO_DN);
  509. cryptDestroyCert(cert);
  510. end;
  511. function TSSLCryptLib.GetPeerName: string;
  512. var
  513. cert: CRYPT_CERTIFICATE;
  514. begin
  515. Result := '';
  516. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  517. Exit;
  518. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  519. cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME);
  520. Result := GetString(cert, CRYPT_CERTINFO_COMMONNAME);
  521. cryptDestroyCert(cert);
  522. end;
  523. function TSSLCryptLib.GetPeerIssuer: string;
  524. var
  525. cert: CRYPT_CERTIFICATE;
  526. begin
  527. Result := '';
  528. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  529. Exit;
  530. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  531. cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_ISSUERNAME);
  532. Result := GetString(cert, CRYPT_CERTINFO_COMMONNAME);
  533. cryptDestroyCert(cert);
  534. end;
  535. function TSSLCryptLib.GetPeerFingerprint: string;
  536. var
  537. cert: CRYPT_CERTIFICATE;
  538. begin
  539. Result := '';
  540. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  541. Exit;
  542. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  543. Result := GetString(cert, CRYPT_CERTINFO_FINGERPRINT);
  544. cryptDestroyCert(cert);
  545. end;
  546. procedure TSSLCryptLib.SetCertCAFile(const Value: string);
  547. var F:textfile;
  548. bInCert:boolean;
  549. s,sCert:string;
  550. cert: CRYPT_CERTIFICATE;
  551. idx:integer;
  552. begin
  553. if assigned(FTrustedCAs) then
  554. begin
  555. for idx := 0 to High(FTrustedCAs) do
  556. cryptDestroyCert(FTrustedCAs[idx]);
  557. FTrustedCAs:=nil;
  558. end;
  559. if Value<>'' then
  560. begin
  561. AssignFile(F,Value);
  562. reset(F);
  563. bInCert:=false;
  564. idx:=0;
  565. while not eof(F) do
  566. begin
  567. readln(F,s);
  568. if pos('-----END CERTIFICATE-----',s)>0 then
  569. begin
  570. bInCert:=false;
  571. cert:=0;
  572. if (cryptImportCert(PAnsiChar(sCert),length(sCert)-2,CRYPT_UNUSED,cert)=CRYPT_OK) then
  573. begin
  574. cryptSetAttribute( cert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, 1 );
  575. SetLength(FTrustedCAs,idx+1);
  576. FTrustedCAs[idx]:=cert;
  577. idx:=idx+1;
  578. end;
  579. end;
  580. if bInCert then
  581. sCert:=sCert+s+#13#10;
  582. if pos('-----BEGIN CERTIFICATE-----',s)>0 then
  583. begin
  584. bInCert:=true;
  585. sCert:='';
  586. end;
  587. end;
  588. CloseFile(F);
  589. end;
  590. end;
  591. function TSSLCryptLib.GetVerifyCert: integer;
  592. var
  593. cert: CRYPT_CERTIFICATE;
  594. itype,ilocus:integer;
  595. begin
  596. Result := -1;
  597. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  598. Exit;
  599. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  600. result:=cryptCheckCert(cert,CRYPT_UNUSED);
  601. if result<>CRYPT_OK then
  602. begin
  603. //get extended error info if available
  604. cryptGetAttribute(cert,CRYPT_ATTRIBUTE_ERRORtype,itype);
  605. cryptGetAttribute(cert,CRYPT_ATTRIBUTE_ERRORLOCUS,ilocus);
  606. cryptSetAttribute(cert, CRYPT_ATTRIBUTE_CURRENT, CRYPT_CERTINFO_SUBJECTNAME);
  607. FLastError := Result;
  608. FLastErrorDesc := format('SSL/TLS certificate verification failed for "%s"'#13#10'Status: %d. ERRORTYPE: %d. ERRORLOCUS: %d.',
  609. [GetString(cert, CRYPT_CERTINFO_COMMONNAME),result,itype,ilocus]);
  610. end;
  611. cryptDestroyCert(cert);
  612. end;
  613. {==============================================================================}
  614. var imajor,iminor,iver:integer;
  615. // e: ESynapseError;
  616. initialization
  617. if cryptInit = CRYPT_OK then
  618. SSLImplementation := TSSLCryptLib;
  619. cryptAddRandom(nil, CRYPT_RANDOM_SLOWPOLL);
  620. cryptGetAttribute (CRYPT_UNUSED, CRYPT_OPTION_INFO_MAJORVERSION,imajor);
  621. cryptGetAttribute (CRYPT_UNUSED, CRYPT_OPTION_INFO_MINORVERSION,iminor);
  622. // according to the documentation CRYPTLIB version has 3 digits. recent versions use 4 digits
  623. if CRYPTLIB_VERSION >1000 then
  624. iver:=CRYPTLIB_VERSION div 100
  625. else
  626. iver:=CRYPTLIB_VERSION div 10;
  627. if (iver <> imajor*10+iminor) then
  628. begin
  629. SSLImplementation :=TSSLNone;
  630. // e := ESynapseError.Create(format('Error wrong cryptlib version (is %d.%d expected %d.%d). ',
  631. // [imajor,iminor,iver div 10, iver mod 10]));
  632. // e.ErrorCode := 0;
  633. // e.ErrorMessage := format('Error wrong cryptlib version (%d.%d expected %d.%d)',
  634. // [imajor,iminor,iver div 10, iver mod 10]);
  635. // raise e;
  636. end;
  637. finalization
  638. cryptEnd;
  639. end.