ssl_cryptlib.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. {==============================================================================|
  2. | Project : Ararat Synapse | 001.001.000 |
  3. |==============================================================================|
  4. | Content: SSL/SSH support by Peter Gutmann's CryptLib |
  5. |==============================================================================|
  6. | Copyright (c)1999-2005, 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. |
  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. unit ssl_cryptlib;
  74. interface
  75. uses
  76. SysUtils,
  77. blcksock, synsock, synautil, synacode,
  78. cryptlib;
  79. type
  80. {:@abstract(class implementing CryptLib SSL/SSH plugin.)
  81. Instance of this class will be created for each @link(TTCPBlockSocket).
  82. You not need to create instance of this class, all is done by Synapse itself!}
  83. TSSLCryptLib = class(TCustomSSL)
  84. protected
  85. FCryptSession: CRYPT_SESSION;
  86. FPrivateKeyLabel: string;
  87. FDelCert: Boolean;
  88. FReadBuffer: string;
  89. function SSLCheck(Value: integer): Boolean;
  90. function Init(server:Boolean): Boolean;
  91. function DeInit: Boolean;
  92. function Prepare(server:Boolean): Boolean;
  93. function GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string;
  94. function CreateSelfSignedCert(Host: string): Boolean; override;
  95. function PopAll: string;
  96. public
  97. {:See @inherited}
  98. constructor Create(const Value: TTCPBlockSocket); override;
  99. destructor Destroy; override;
  100. {:See @inherited}
  101. function LibVersion: String; override;
  102. {:See @inherited}
  103. function LibName: String; override;
  104. {:See @inherited}
  105. procedure Assign(const Value: TCustomSSL); override;
  106. {:See @inherited and @link(ssl_cryptlib) for more details.}
  107. function Connect: boolean; override;
  108. {:See @inherited and @link(ssl_cryptlib) for more details.}
  109. function Accept: boolean; override;
  110. {:See @inherited}
  111. function Shutdown: boolean; override;
  112. {:See @inherited}
  113. function BiShutdown: boolean; override;
  114. {:See @inherited}
  115. function SendBuffer(Buffer: TMemory; Len: Integer): Integer; override;
  116. {:See @inherited}
  117. function RecvBuffer(Buffer: TMemory; Len: Integer): Integer; override;
  118. {:See @inherited}
  119. function WaitingData: Integer; override;
  120. {:See @inherited}
  121. function GetSSLVersion: string; override;
  122. {:See @inherited}
  123. function GetPeerSubject: string; override;
  124. {:See @inherited}
  125. function GetPeerIssuer: string; override;
  126. {:See @inherited}
  127. function GetPeerName: string; override;
  128. {:See @inherited}
  129. function GetPeerFingerprint: string; override;
  130. published
  131. {:name of certificate/key within PKCS#15 file. It can hold more then one
  132. certificate/key and each certificate/key must have unique label within one file.}
  133. property PrivateKeyLabel: string read FPrivateKeyLabel Write FPrivateKeyLabel;
  134. end;
  135. implementation
  136. {==============================================================================}
  137. constructor TSSLCryptLib.Create(const Value: TTCPBlockSocket);
  138. begin
  139. inherited Create(Value);
  140. FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
  141. FPrivateKeyLabel := 'synapse';
  142. FDelCert := false;
  143. end;
  144. destructor TSSLCryptLib.Destroy;
  145. begin
  146. DeInit;
  147. inherited Destroy;
  148. end;
  149. procedure TSSLCryptLib.Assign(const Value: TCustomSSL);
  150. begin
  151. inherited Assign(Value);
  152. if Value is TSSLCryptLib then
  153. begin
  154. FPrivateKeyLabel := TSSLCryptLib(Value).privatekeyLabel;
  155. end;
  156. end;
  157. function TSSLCryptLib.GetString(const cryptHandle: CRYPT_HANDLE; const attributeType: CRYPT_ATTRIBUTE_TYPE): string;
  158. var
  159. l: integer;
  160. begin
  161. l := 0;
  162. cryptGetAttributeString(cryptHandle, attributeType, nil, l);
  163. setlength(Result, l);
  164. cryptGetAttributeString(cryptHandle, attributeType, pointer(Result), l);
  165. setlength(Result, l);
  166. end;
  167. function TSSLCryptLib.LibVersion: String;
  168. var
  169. x: integer;
  170. begin
  171. Result := GetString(CRYPT_UNUSED, CRYPT_OPTION_INFO_DESCRIPTION);
  172. cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_MAJORVERSION, x);
  173. Result := Result + ' v' + IntToStr(x);
  174. cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_MINORVERSION, x);
  175. Result := Result + '.' + IntToStr(x);
  176. cryptGetAttribute(CRYPT_UNUSED, CRYPT_OPTION_INFO_STEPPING, x);
  177. Result := Result + '.' + IntToStr(x);
  178. end;
  179. function TSSLCryptLib.LibName: String;
  180. begin
  181. Result := 'ssl_cryptlib';
  182. end;
  183. function TSSLCryptLib.SSLCheck(Value: integer): Boolean;
  184. begin
  185. Result := true;
  186. FLastErrorDesc := '';
  187. if Value = CRYPT_ERROR_COMPLETE then
  188. Value := 0;
  189. FLastError := Value;
  190. if FLastError <> 0 then
  191. begin
  192. Result := False;
  193. FLastErrorDesc := GetString(FCryptSession, CRYPT_ATTRIBUTE_INT_ERRORMESSAGE);
  194. end;
  195. end;
  196. function TSSLCryptLib.CreateSelfSignedCert(Host: string): Boolean;
  197. var
  198. privateKey: CRYPT_CONTEXT;
  199. keyset: CRYPT_KEYSET;
  200. cert: CRYPT_CERTIFICATE;
  201. publicKey: CRYPT_CONTEXT;
  202. begin
  203. Result := False;
  204. if FPrivatekeyFile = '' then
  205. FPrivatekeyFile := GetTempFile('', 'key');
  206. cryptCreateContext(privateKey, CRYPT_UNUSED, CRYPT_ALGO_RSA);
  207. cryptSetAttributeString(privateKey, CRYPT_CTXINFO_LABEL, Pointer(FPrivatekeyLabel),
  208. Length(FPrivatekeyLabel));
  209. cryptSetAttribute(privateKey, CRYPT_CTXINFO_KEYSIZE, 1024);
  210. cryptGenerateKey(privateKey);
  211. cryptKeysetOpen(keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, PChar(FPrivatekeyFile), CRYPT_KEYOPT_CREATE);
  212. FDelCert := True;
  213. cryptAddPrivateKey(keyset, privateKey, PChar(FKeyPassword));
  214. cryptCreateCert(cert, CRYPT_UNUSED, CRYPT_CERTTYPE_CERTIFICATE);
  215. cryptSetAttribute(cert, CRYPT_CERTINFO_XYZZY, 1);
  216. cryptGetPublicKey(keyset, publicKey, CRYPT_KEYID_NAME, PChar(FPrivatekeyLabel));
  217. cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, publicKey);
  218. cryptSetAttributeString(cert, CRYPT_CERTINFO_COMMONNAME, Pointer(host), Length(host));
  219. cryptSignCert(cert, privateKey);
  220. cryptAddPublicKey(keyset, cert);
  221. cryptKeysetClose(keyset);
  222. cryptDestroyCert(cert);
  223. cryptDestroyContext(privateKey);
  224. cryptDestroyContext(publicKey);
  225. Result := True;
  226. end;
  227. function TSSLCryptLib.PopAll: string;
  228. const
  229. BufferMaxSize = 32768;
  230. var
  231. Outbuffer: string;
  232. WriteLen: integer;
  233. begin
  234. Result := '';
  235. repeat
  236. setlength(outbuffer, BufferMaxSize);
  237. Writelen := 0;
  238. SSLCheck(CryptPopData(FCryptSession, @OutBuffer[1], BufferMaxSize, Writelen));
  239. if FLastError <> 0 then
  240. Break;
  241. if WriteLen > 0 then
  242. begin
  243. setlength(outbuffer, WriteLen);
  244. Result := Result + outbuffer;
  245. end;
  246. until WriteLen = 0;
  247. end;
  248. function TSSLCryptLib.Init(server:Boolean): Boolean;
  249. var
  250. st: CRYPT_SESSION_TYPE;
  251. keysetobj: CRYPT_KEYSET;
  252. cryptContext: CRYPT_CONTEXT;
  253. x: integer;
  254. begin
  255. Result := False;
  256. FLastErrorDesc := '';
  257. FLastError := 0;
  258. FDelCert := false;
  259. FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
  260. if server then
  261. case FSSLType of
  262. LT_all, LT_SSLv3, LT_TLSv1, LT_TLSv1_1:
  263. st := CRYPT_SESSION_SSL_SERVER;
  264. LT_SSHv2:
  265. st := CRYPT_SESSION_SSH_SERVER;
  266. else
  267. Exit;
  268. end
  269. else
  270. case FSSLType of
  271. LT_all, LT_SSLv3, LT_TLSv1, LT_TLSv1_1:
  272. st := CRYPT_SESSION_SSL;
  273. LT_SSHv2:
  274. st := CRYPT_SESSION_SSH;
  275. else
  276. Exit;
  277. end;
  278. if not SSLCheck(cryptCreateSession(FcryptSession, CRYPT_UNUSED, st)) then
  279. Exit;
  280. x := -1;
  281. case FSSLType of
  282. LT_SSLv3:
  283. x := 0;
  284. LT_TLSv1:
  285. x := 1;
  286. LT_TLSv1_1:
  287. x := 2;
  288. end;
  289. if x >= 0 then
  290. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_VERSION, x)) then
  291. Exit;
  292. if FUsername <> '' then
  293. begin
  294. cryptSetAttributeString(FcryptSession, CRYPT_SESSINFO_USERNAME,
  295. Pointer(FUsername), Length(FUsername));
  296. cryptSetAttributeString(FcryptSession, CRYPT_SESSINFO_PASSWORD,
  297. Pointer(FPassword), Length(FPassword));
  298. end;
  299. if FSSLType = LT_SSHv2 then
  300. if FSSHChannelType <> '' then
  301. begin
  302. cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL, CRYPT_UNUSED);
  303. cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_TYPE,
  304. Pointer(FSSHChannelType), Length(FSSHChannelType));
  305. if FSSHChannelArg1 <> '' then
  306. cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_ARG1,
  307. Pointer(FSSHChannelArg1), Length(FSSHChannelArg1));
  308. if FSSHChannelArg2 <> '' then
  309. cryptSetAttributeString(FCryptSession, CRYPT_SESSINFO_SSH_CHANNEL_ARG2,
  310. Pointer(FSSHChannelArg2), Length(FSSHChannelArg2));
  311. end;
  312. if server and (FPrivatekeyFile = '') then
  313. begin
  314. if FPrivatekeyLabel = '' then
  315. FPrivatekeyLabel := 'synapse';
  316. if FkeyPassword = '' then
  317. FkeyPassword := 'synapse';
  318. CreateSelfSignedcert(FSocket.ResolveIPToName(FSocket.GetRemoteSinIP));
  319. end;
  320. if (FPrivatekeyLabel <> '') and (FPrivatekeyFile <> '') then
  321. begin
  322. if not SSLCheck(cryptKeysetOpen(KeySetObj, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
  323. PChar(FPrivatekeyFile), CRYPT_KEYOPT_READONLY)) then
  324. Exit;
  325. try
  326. if not SSLCheck(cryptGetPrivateKey(KeySetObj, cryptcontext, CRYPT_KEYID_NAME,
  327. PChar(FPrivatekeyLabel), PChar(FKeyPassword))) then
  328. Exit;
  329. if not SSLCheck(cryptSetAttribute(FcryptSession, CRYPT_SESSINFO_PRIVATEKEY,
  330. cryptcontext)) then
  331. Exit;
  332. finally
  333. cryptKeysetClose(keySetObj);
  334. cryptDestroyContext(cryptcontext);
  335. end;
  336. end;
  337. if server and FVerifyCert then
  338. begin
  339. if not SSLCheck(cryptKeysetOpen(KeySetObj, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
  340. PChar(FCertCAFile), CRYPT_KEYOPT_READONLY)) then
  341. Exit;
  342. try
  343. if not SSLCheck(cryptSetAttribute(FcryptSession, CRYPT_SESSINFO_KEYSET,
  344. keySetObj)) then
  345. Exit;
  346. finally
  347. cryptKeysetClose(keySetObj);
  348. end;
  349. end;
  350. Result := true;
  351. end;
  352. function TSSLCryptLib.DeInit: Boolean;
  353. begin
  354. Result := True;
  355. if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then
  356. CryptDestroySession(FcryptSession);
  357. FcryptSession := CRYPT_SESSION(CRYPT_SESSION_NONE);
  358. FSSLEnabled := False;
  359. if FDelCert then
  360. Deletefile(FPrivatekeyFile);
  361. end;
  362. function TSSLCryptLib.Prepare(server:Boolean): Boolean;
  363. begin
  364. Result := false;
  365. DeInit;
  366. if Init(server) then
  367. Result := true
  368. else
  369. DeInit;
  370. end;
  371. function TSSLCryptLib.Connect: boolean;
  372. begin
  373. Result := False;
  374. if FSocket.Socket = INVALID_SOCKET then
  375. Exit;
  376. if Prepare(false) then
  377. begin
  378. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_NETWORKSOCKET, FSocket.Socket)) then
  379. Exit;
  380. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 1)) then
  381. Exit;
  382. FSSLEnabled := True;
  383. Result := True;
  384. FReadBuffer := '';
  385. end;
  386. end;
  387. function TSSLCryptLib.Accept: boolean;
  388. begin
  389. Result := False;
  390. if FSocket.Socket = INVALID_SOCKET then
  391. Exit;
  392. if Prepare(true) then
  393. begin
  394. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_NETWORKSOCKET, FSocket.Socket)) then
  395. Exit;
  396. if not SSLCheck(cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 1)) then
  397. Exit;
  398. FSSLEnabled := True;
  399. Result := True;
  400. FReadBuffer := '';
  401. end;
  402. end;
  403. function TSSLCryptLib.Shutdown: boolean;
  404. begin
  405. Result := BiShutdown;
  406. end;
  407. function TSSLCryptLib.BiShutdown: boolean;
  408. begin
  409. if FcryptSession <> CRYPT_SESSION(CRYPT_SESSION_NONE) then
  410. cryptSetAttribute(FCryptSession, CRYPT_SESSINFO_ACTIVE, 0);
  411. DeInit;
  412. FReadBuffer := '';
  413. Result := True;
  414. end;
  415. function TSSLCryptLib.SendBuffer(Buffer: TMemory; Len: Integer): Integer;
  416. var
  417. l: integer;
  418. begin
  419. FLastError := 0;
  420. FLastErrorDesc := '';
  421. SSLCheck(cryptPushData(FCryptSession, Buffer, Len, L));
  422. cryptFlushData(FcryptSession);
  423. Result := l;
  424. end;
  425. function TSSLCryptLib.RecvBuffer(Buffer: TMemory; Len: Integer): Integer;
  426. var
  427. l: integer;
  428. begin
  429. FLastError := 0;
  430. FLastErrorDesc := '';
  431. if Length(FReadBuffer) = 0 then
  432. FReadBuffer := PopAll;
  433. if Len > Length(FReadBuffer) then
  434. Len := Length(FReadBuffer);
  435. Move(Pointer(FReadBuffer)^, buffer^, Len);
  436. Delete(FReadBuffer, 1, Len);
  437. Result := Len;
  438. end;
  439. function TSSLCryptLib.WaitingData: Integer;
  440. begin
  441. Result := Length(FReadBuffer);
  442. end;
  443. function TSSLCryptLib.GetSSLVersion: string;
  444. var
  445. x: integer;
  446. begin
  447. Result := '';
  448. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  449. Exit;
  450. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_VERSION, x);
  451. if FSSLType in [LT_SSLv3, LT_TLSv1, LT_TLSv1_1, LT_all] then
  452. case x of
  453. 0:
  454. Result := 'SSLv3';
  455. 1:
  456. Result := 'TLSv1';
  457. 2:
  458. Result := 'TLSv1.1';
  459. end;
  460. if FSSLType in [LT_SSHv2] then
  461. case x of
  462. 0:
  463. Result := 'SSHv1';
  464. 1:
  465. Result := 'SSHv2';
  466. end;
  467. end;
  468. function TSSLCryptLib.GetPeerSubject: string;
  469. var
  470. cert: CRYPT_CERTIFICATE;
  471. begin
  472. Result := '';
  473. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  474. Exit;
  475. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  476. cryptSetAttribute(cert, CRYPT_CERTINFO_SUBJECTNAME, CRYPT_UNUSED);
  477. Result := GetString(cert, CRYPT_CERTINFO_DN);
  478. cryptDestroyCert(cert);
  479. end;
  480. function TSSLCryptLib.GetPeerName: string;
  481. var
  482. cert: CRYPT_CERTIFICATE;
  483. begin
  484. Result := '';
  485. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  486. Exit;
  487. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  488. cryptSetAttribute(cert, CRYPT_CERTINFO_ISSUERNAME, CRYPT_UNUSED);
  489. Result := GetString(cert, CRYPT_CERTINFO_COMMONNAME);
  490. cryptDestroyCert(cert);
  491. end;
  492. function TSSLCryptLib.GetPeerIssuer: string;
  493. var
  494. cert: CRYPT_CERTIFICATE;
  495. begin
  496. Result := '';
  497. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  498. Exit;
  499. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  500. cryptSetAttribute(cert, CRYPT_CERTINFO_ISSUERNAME, CRYPT_UNUSED);
  501. Result := GetString(cert, CRYPT_CERTINFO_DN);
  502. cryptDestroyCert(cert);
  503. end;
  504. function TSSLCryptLib.GetPeerFingerprint: string;
  505. var
  506. cert: CRYPT_CERTIFICATE;
  507. begin
  508. Result := '';
  509. if FcryptSession = CRYPT_SESSION(CRYPT_SESSION_NONE) then
  510. Exit;
  511. cryptGetAttribute(FCryptSession, CRYPT_SESSINFO_RESPONSE, cert);
  512. Result := GetString(cert, CRYPT_CERTINFO_FINGERPRINT);
  513. Result := MD5(Result);
  514. cryptDestroyCert(cert);
  515. end;
  516. {==============================================================================}
  517. initialization
  518. if cryptInit = CRYPT_OK then
  519. SSLImplementation := TSSLCryptLib;
  520. cryptAddRandom(nil, CRYPT_RANDOM_SLOWPOLL);
  521. finalization
  522. cryptEnd;
  523. end.