ssl_winssl_lib.pas 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911
  1. {
  2. SChannel to OpenSSL wrapper
  3. Copyright (c) 2008 Boris Krasnovskiy
  4. Copyright (c) 2013-2015 Alexander Koblov (pascal port)
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. }
  16. unit ssl_winssl_lib;
  17. {$mode delphi}
  18. interface
  19. uses
  20. Windows, SynSock, JwaSspi, CTypes;
  21. type
  22. PSSL_CTX = ^SSL_CTX;
  23. SSL_CTX = record
  24. dwProtocol: DWORD;
  25. bVerify: BOOL;
  26. end;
  27. PSSL_METHOD = ^SSL_METHOD;
  28. SSL_METHOD = record
  29. dummy: DWORD;
  30. end;
  31. PSSL = ^SSL;
  32. SSL = record
  33. s: TSocket;
  34. ctx: PSSL_CTX;
  35. hContext: CtxtHandle;
  36. hCreds: CredHandle;
  37. pbRecDataBuf: PByte;
  38. cbRecDataBuf: LONG;
  39. sbRecDataBuf: LONG;
  40. pbIoBuffer: PByte;
  41. cbIoBuffer: LONG;
  42. sbIoBuffer: LONG;
  43. exIoBuffer: BOOL;
  44. rmshtdn: BOOL;
  45. end;
  46. function SSL_library_init(): cint; cdecl;
  47. function SSL_set_fd(ssl: PSSL; fd: cint): cint; cdecl;
  48. function SSL_CTX_new(method: PSSL_METHOD): PSSL_CTX; cdecl;
  49. procedure SSL_CTX_free(ctx: PSSL_CTX); cdecl;
  50. function SSL_new(ctx: PSSL_CTX): PSSL; cdecl;
  51. procedure SSL_free(ssl: PSSL); cdecl;
  52. function SSL_connect(ssl: PSSL): cint; cdecl;
  53. function SSL_shutdown(ssl: PSSL): cint; cdecl;
  54. function SSL_read(ssl: PSSL; buf: PByte; num: cint): cint; cdecl;
  55. function SSL_write(ssl: PSSL; const buf: PByte; num: cint): cint; cdecl;
  56. function SSL_pending(ssl: PSSL): cint; cdecl;
  57. function SSLv23_method(): PSSL_METHOD; cdecl;
  58. function SSLv2_method(): PSSL_METHOD; cdecl;
  59. function SSLv3_method(): PSSL_METHOD; cdecl;
  60. function TLSv1_method(): PSSL_METHOD; cdecl;
  61. function TLSv1_1_method(): PSSL_METHOD; cdecl;
  62. function TLSv1_2_method(): PSSL_METHOD; cdecl;
  63. procedure SSL_CTX_set_verify(ctx: PSSL_CTX; mode: cint; func: Pointer); cdecl;
  64. function SSL_get_error (ssl: PSSL; ret: cint): cint; cdecl;
  65. implementation
  66. uses
  67. JwaWinError,
  68. ssl_openssl_lib, blcksock, ssl_openssl;
  69. const
  70. SCHANNEL_CRED_VERSION = $00000004;
  71. const
  72. SCH_CRED_MANUAL_CRED_VALIDATION = $00000008;
  73. SCH_CRED_NO_DEFAULT_CREDS = $00000010;
  74. const
  75. SCHANNEL_SHUTDOWN = 1; // gracefully close down a connection
  76. const
  77. SP_PROT_SSL2_SERVER = $00000004;
  78. SP_PROT_SSL2_CLIENT = $00000008;
  79. SP_PROT_SSL2 = (SP_PROT_SSL2_SERVER or SP_PROT_SSL2_CLIENT);
  80. SP_PROT_SSL3_SERVER = $00000010;
  81. SP_PROT_SSL3_CLIENT = $00000020;
  82. SP_PROT_SSL3 = (SP_PROT_SSL3_SERVER or SP_PROT_SSL3_CLIENT);
  83. SP_PROT_TLS1_SERVER = $00000040;
  84. SP_PROT_TLS1_CLIENT = $00000080;
  85. SP_PROT_TLS1 = (SP_PROT_TLS1_SERVER or SP_PROT_TLS1_CLIENT);
  86. SP_PROT_TLS1_1_SERVER = $00000100;
  87. SP_PROT_TLS1_1_CLIENT = $00000200;
  88. SP_PROT_TLS1_1 = (SP_PROT_TLS1_1_SERVER or SP_PROT_TLS1_1_CLIENT);
  89. SP_PROT_TLS1_2_SERVER = $00000400;
  90. SP_PROT_TLS1_2_CLIENT = $00000800;
  91. SP_PROT_TLS1_2 = (SP_PROT_TLS1_2_SERVER or SP_PROT_TLS1_2_CLIENT);
  92. const
  93. UNISP_NAME_A = AnsiString('Microsoft Unified Security Protocol Provider');
  94. UNISP_NAME_W = WideString('Microsoft Unified Security Protocol Provider');
  95. type
  96. ALG_ID = type cuint;
  97. HCERTSTORE = type HANDLE;
  98. PCCERT_CONTEXT = type Pointer;
  99. type
  100. SCHANNEL_CRED = record
  101. dwVersion: DWORD;
  102. cCreds: DWORD;
  103. paCred: PCCERT_CONTEXT;
  104. hRootStore: HCERTSTORE;
  105. cMappers: DWORD;
  106. aphMappers: Pointer;
  107. cSupportedAlgs: DWORD;
  108. palgSupportedAlgs: ^ALG_ID;
  109. grbitEnabledProtocols: DWORD;
  110. dwMinimumCipherStrength: DWORD;
  111. dwMaximumCipherStrength: DWORD;
  112. dwSessionLifespan: DWORD;
  113. dwFlags: DWORD;
  114. dwCredFormat: DWORD;
  115. end;
  116. var
  117. g_hSecurity: HMODULE;
  118. g_pSSPI: PSecurityFunctionTableA;
  119. function SSL_library_init(): cint; cdecl;
  120. var
  121. pInitSecurityInterface: INIT_SECURITY_INTERFACE_A;
  122. begin
  123. if (g_hSecurity <> 0) then Exit(1);
  124. g_hSecurity:= LoadLibraryA('schannel.dll');
  125. if (g_hSecurity = 0) then Exit(0);
  126. pInitSecurityInterface := INIT_SECURITY_INTERFACE_A(GetProcAddress(g_hSecurity, SECURITY_ENTRYPOINT_ANSIA));
  127. if (pInitSecurityInterface <> nil) then
  128. g_pSSPI := pInitSecurityInterface();
  129. if (g_pSSPI = nil) then
  130. begin
  131. FreeLibrary(g_hSecurity);
  132. g_hSecurity := 0;
  133. Exit(0);
  134. end;
  135. Result := 1;
  136. end;
  137. function SSL_set_fd(ssl: PSSL; fd: cint): cint; cdecl;
  138. begin
  139. if (ssl = nil) then Exit(0);
  140. ssl^.s := TSocket(fd);
  141. Result := 1;
  142. end;
  143. function SSL_CTX_new(method: PSSL_METHOD): PSSL_CTX; cdecl;
  144. begin
  145. if (g_hSecurity = 0) then Exit(nil);
  146. Result := GetMem(SizeOf(SSL_CTX));
  147. Result^.dwProtocol := DWORD(method);
  148. end;
  149. procedure SSL_CTX_free(ctx: PSSL_CTX); cdecl;
  150. begin
  151. FreeMem(ctx);
  152. end;
  153. function SSL_new(ctx: PSSL_CTX): PSSL; cdecl;
  154. var
  155. SchannelCred: SCHANNEL_CRED;
  156. tsExpiry: TimeStamp;
  157. scRet: SECURITY_STATUS;
  158. begin
  159. if (ctx = nil) then Exit(nil);
  160. Result := GetMem(SizeOf(SSL));
  161. ZeroMemory(Result, SizeOf(SSL));
  162. Result^.ctx := ctx;
  163. ZeroMemory(@SchannelCred, SizeOf(SchannelCred));
  164. SchannelCred.dwVersion := SCHANNEL_CRED_VERSION;
  165. SchannelCred.grbitEnabledProtocols := ctx^.dwProtocol;
  166. SchannelCred.dwFlags := SchannelCred.dwFlags or SCH_CRED_NO_DEFAULT_CREDS;
  167. if (not ctx^.bVerify) then
  168. SchannelCred.dwFlags := SchannelCred.dwFlags or SCH_CRED_MANUAL_CRED_VALIDATION;
  169. // Create an SSPI credential.
  170. scRet := g_pSSPI^.AcquireCredentialsHandleA(
  171. nil, // Name of principal
  172. UNISP_NAME_A, // Name of package
  173. SECPKG_CRED_OUTBOUND, // Flags indicating use
  174. nil, // Pointer to logon ID
  175. @SchannelCred, // Package specific data
  176. nil, // Pointer to GetKey() func
  177. nil, // Value to pass to GetKey()
  178. @Result^.hCreds, // (out) Cred Handle
  179. @tsExpiry); // (out) Lifetime (optional)
  180. if (scRet <> SEC_E_OK) then
  181. begin
  182. FreeMem(Result);
  183. Result := nil;
  184. end;
  185. end;
  186. procedure SSL_free(ssl: PSSL); cdecl;
  187. begin
  188. if (ssl = nil) then Exit;
  189. g_pSSPI^.FreeCredentialHandle(@ssl^.hCreds);
  190. g_pSSPI^.DeleteSecurityContext(@ssl^.hContext);
  191. FreeMem(ssl^.pbRecDataBuf);
  192. FreeMem(ssl^.pbIoBuffer);
  193. FreeMem(ssl);
  194. end;
  195. function ClientHandshakeLoop(ssl: PSSL; fDoInitialRead: BOOL): SECURITY_STATUS;
  196. var
  197. InBuffer: SecBufferDesc;
  198. InBuffers: array [0..1] of SecBuffer;
  199. OutBuffer: SecBufferDesc;
  200. OutBuffers: array [0..0] of SecBuffer;
  201. dwSSPIFlags: DWORD;
  202. dwSSPIOutFlags: DWORD = 0;
  203. tsExpiry: TimeStamp;
  204. scRet: SECURITY_STATUS;
  205. cbData: LONG;
  206. fDoRead: BOOL;
  207. tv: TTimeVal = (tv_sec: 10; tv_usec: 0);
  208. fd: TFDSet;
  209. begin
  210. dwSSPIFlags := ISC_REQ_SEQUENCE_DETECT or
  211. ISC_REQ_REPLAY_DETECT or
  212. ISC_REQ_CONFIDENTIALITY or
  213. ISC_RET_EXTENDED_ERROR or
  214. ISC_REQ_ALLOCATE_MEMORY or
  215. ISC_REQ_STREAM;
  216. ssl^.cbIoBuffer := 0;
  217. fDoRead := fDoInitialRead;
  218. scRet := SEC_I_CONTINUE_NEEDED;
  219. // Loop until the handshake is finished or an error occurs.
  220. while (scRet = SEC_I_CONTINUE_NEEDED) or
  221. (scRet = SEC_E_INCOMPLETE_MESSAGE) or
  222. (scRet = SEC_I_INCOMPLETE_CREDENTIALS) do
  223. begin
  224. // Read server data
  225. if (0 = ssl^.cbIoBuffer) or (scRet = SEC_E_INCOMPLETE_MESSAGE) then
  226. begin
  227. if (fDoRead) then
  228. begin
  229. // If buffer not large enough reallocate buffer
  230. if (ssl^.sbIoBuffer <= ssl^.cbIoBuffer) then
  231. begin
  232. ssl^.sbIoBuffer += 2048;
  233. ssl^.pbIoBuffer := PUCHAR(ReAllocMem(ssl^.pbIoBuffer, ssl^.sbIoBuffer));
  234. end;
  235. FD_ZERO(fd);
  236. FD_SET(ssl^.s, fd);
  237. if (select(1, @fd, nil, nil, @tv) <> 1) then
  238. begin
  239. scRet := SEC_E_INTERNAL_ERROR;
  240. break;
  241. end;
  242. cbData := recv(ssl^.s,
  243. ssl^.pbIoBuffer + ssl^.cbIoBuffer,
  244. ssl^.sbIoBuffer - ssl^.cbIoBuffer,
  245. 0);
  246. if (cbData = SOCKET_ERROR) then
  247. begin
  248. scRet := SEC_E_INTERNAL_ERROR;
  249. break;
  250. end
  251. else if (cbData = 0) then
  252. begin
  253. scRet := SEC_E_INTERNAL_ERROR;
  254. break;
  255. end;
  256. ssl^.cbIoBuffer += cbData;
  257. end
  258. else begin
  259. fDoRead := TRUE;
  260. end;
  261. end;
  262. // Set up the input buffers. Buffer 0 is used to pass in data
  263. // received from the server. Schannel will consume some or all
  264. // of this. Leftover data (if any) will be placed in buffer 1 and
  265. // given a buffer type of SECBUFFER_EXTRA.
  266. InBuffers[0].pvBuffer := ssl^.pbIoBuffer;
  267. InBuffers[0].cbBuffer := ssl^.cbIoBuffer;
  268. InBuffers[0].BufferType := SECBUFFER_TOKEN;
  269. InBuffers[1].pvBuffer := nil;
  270. InBuffers[1].cbBuffer := 0;
  271. InBuffers[1].BufferType := SECBUFFER_EMPTY;
  272. InBuffer.cBuffers := 2;
  273. InBuffer.pBuffers := InBuffers;
  274. InBuffer.ulVersion := SECBUFFER_VERSION;
  275. // Set up the output buffers. These are initialized to NULL
  276. // so as to make it less likely we'll attempt to free random
  277. // garbage later.
  278. OutBuffers[0].pvBuffer := nil;
  279. OutBuffers[0].BufferType:= SECBUFFER_TOKEN;
  280. OutBuffers[0].cbBuffer := 0;
  281. OutBuffer.cBuffers := 1;
  282. OutBuffer.pBuffers := OutBuffers;
  283. OutBuffer.ulVersion := SECBUFFER_VERSION;
  284. scRet := g_pSSPI^.InitializeSecurityContextA(@ssl^.hCreds,
  285. @ssl^.hContext,
  286. nil,
  287. dwSSPIFlags,
  288. 0,
  289. SECURITY_NATIVE_DREP,
  290. @InBuffer,
  291. 0,
  292. nil,
  293. @OutBuffer,
  294. dwSSPIOutFlags,
  295. @tsExpiry);
  296. // If success (or if the error was one of the special extended ones),
  297. // send the contents of the output buffer to the server.
  298. if (scRet = SEC_E_OK) or
  299. (scRet = SEC_I_CONTINUE_NEEDED) or
  300. (FAILED(scRet) and (dwSSPIOutFlags and ISC_RET_EXTENDED_ERROR <> 0)) then
  301. begin
  302. if (OutBuffers[0].cbBuffer <> 0) and (OutBuffers[0].pvBuffer <> nil) then
  303. begin
  304. cbData := send(ssl^.s,
  305. OutBuffers[0].pvBuffer,
  306. OutBuffers[0].cbBuffer,
  307. 0);
  308. if (cbData = SOCKET_ERROR) or (cbData = 0) then
  309. begin
  310. g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer);
  311. g_pSSPI^.DeleteSecurityContext(@ssl^.hContext);
  312. Exit(SEC_E_INTERNAL_ERROR);
  313. end;
  314. // Free output buffer.
  315. g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer);
  316. OutBuffers[0].pvBuffer := nil;
  317. end;
  318. end;
  319. // we need to read more data from the server and try again.
  320. if (scRet = SEC_E_INCOMPLETE_MESSAGE) then continue;
  321. // handshake completed successfully.
  322. if (scRet = SEC_E_OK) then
  323. begin
  324. // Store remaining data for further use
  325. if (InBuffers[1].BufferType = SECBUFFER_EXTRA) then
  326. begin
  327. ssl^.exIoBuffer := True;
  328. MoveMemory(ssl^.pbIoBuffer,
  329. ssl^.pbIoBuffer + (ssl^.cbIoBuffer - InBuffers[1].cbBuffer),
  330. InBuffers[1].cbBuffer);
  331. ssl^.cbIoBuffer := InBuffers[1].cbBuffer;
  332. end
  333. else
  334. ssl^.cbIoBuffer := 0;
  335. break;
  336. end;
  337. // Check for fatal error.
  338. if (FAILED(scRet)) then break;
  339. // server just requested client authentication.
  340. if (scRet = SEC_I_INCOMPLETE_CREDENTIALS) then
  341. begin
  342. // Server has requested client authentication and
  343. // GetNewClientCredentials(ssl);
  344. // Go around again.
  345. fDoRead := FALSE;
  346. scRet := SEC_I_CONTINUE_NEEDED;
  347. continue;
  348. end;
  349. // Copy any leftover data from the buffer, and go around again.
  350. if ( InBuffers[1].BufferType = SECBUFFER_EXTRA ) then
  351. begin
  352. ssl^.exIoBuffer := True;
  353. MoveMemory(ssl^.pbIoBuffer,
  354. ssl^.pbIoBuffer + (ssl^.cbIoBuffer - InBuffers[1].cbBuffer),
  355. InBuffers[1].cbBuffer);
  356. ssl^.cbIoBuffer := InBuffers[1].cbBuffer;
  357. end
  358. else
  359. ssl^.cbIoBuffer := 0;
  360. end;
  361. // Delete the security context in the case of a fatal error.
  362. if (FAILED(scRet)) then
  363. begin
  364. g_pSSPI^.DeleteSecurityContext(@ssl^.hContext);
  365. end;
  366. if (ssl^.cbIoBuffer = 0) then
  367. begin
  368. FreeMem(ssl^.pbIoBuffer);
  369. ssl^.pbIoBuffer := nil;
  370. ssl^.sbIoBuffer := 0;
  371. end;
  372. Result := scRet;
  373. end;
  374. function SSL_connect(ssl: PSSL): cint; cdecl;
  375. var
  376. OutBuffer: SecBufferDesc;
  377. OutBuffers: array[0..0] of SecBuffer;
  378. dwSSPIFlags: DWORD;
  379. dwSSPIOutFlags: DWORD = 0;
  380. tsExpiry: TimeStamp;
  381. scRet: SECURITY_STATUS;
  382. cbData: LONG;
  383. sock: TVarSin;
  384. begin
  385. if (ssl = nil) then Exit(0);
  386. dwSSPIFlags := ISC_REQ_SEQUENCE_DETECT or
  387. ISC_REQ_REPLAY_DETECT or
  388. ISC_REQ_CONFIDENTIALITY or
  389. ISC_RET_EXTENDED_ERROR or
  390. ISC_REQ_ALLOCATE_MEMORY or
  391. ISC_REQ_STREAM;
  392. // Initiate a ClientHello message and generate a token.
  393. OutBuffers[0].pvBuffer := nil;
  394. OutBuffers[0].BufferType := SECBUFFER_TOKEN;
  395. OutBuffers[0].cbBuffer := 0;
  396. OutBuffer.cBuffers := 1;
  397. OutBuffer.pBuffers := OutBuffers;
  398. OutBuffer.ulVersion := SECBUFFER_VERSION;
  399. GetPeerName(ssl^.s, sock);
  400. scRet := g_pSSPI^.InitializeSecurityContextA(
  401. @ssl^.hCreds,
  402. nil,
  403. inet_ntoa(sock.sin_addr),
  404. dwSSPIFlags,
  405. 0,
  406. SECURITY_NATIVE_DREP,
  407. nil,
  408. 0,
  409. @ssl^.hContext,
  410. @OutBuffer,
  411. dwSSPIOutFlags,
  412. @tsExpiry);
  413. if (scRet <> SEC_I_CONTINUE_NEEDED) then
  414. begin
  415. Exit(0);
  416. end;
  417. // Send response to server if there is one.
  418. if (OutBuffers[0].cbBuffer <> 0) and (OutBuffers[0].pvBuffer <> nil) then
  419. begin
  420. cbData := send(ssl^.s,
  421. OutBuffers[0].pvBuffer,
  422. OutBuffers[0].cbBuffer,
  423. 0);
  424. if (cbData = SOCKET_ERROR) or (cbData = 0) then
  425. begin
  426. g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer);
  427. g_pSSPI^.DeleteSecurityContext(@ssl^.hContext);
  428. Exit(0);
  429. end;
  430. // Free output buffer.
  431. g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer);
  432. OutBuffers[0].pvBuffer := nil;
  433. end;
  434. Result := cint(ClientHandshakeLoop(ssl, TRUE) = SEC_E_OK);
  435. end;
  436. function SSL_shutdown(ssl: PSSL): cint; cdecl;
  437. var
  438. dwType: DWORD;
  439. OutBuffer: SecBufferDesc;
  440. OutBuffers: array[0..0] of SecBuffer;
  441. dwSSPIFlags: DWORD;
  442. dwSSPIOutFlags: DWORD = 0;
  443. tsExpiry: TimeStamp;
  444. Status: DWORD;
  445. begin
  446. if (ssl = nil) then Exit(SOCKET_ERROR);
  447. dwType := SCHANNEL_SHUTDOWN;
  448. OutBuffers[0].pvBuffer := @dwType;
  449. OutBuffers[0].BufferType := SECBUFFER_TOKEN;
  450. OutBuffers[0].cbBuffer := SizeOf(dwType);
  451. OutBuffer.cBuffers := 1;
  452. OutBuffer.pBuffers := OutBuffers;
  453. OutBuffer.ulVersion := SECBUFFER_VERSION;
  454. Status := g_pSSPI^.ApplyControlToken(@ssl^.hContext, @OutBuffer);
  455. if (FAILED(Status)) then Exit(cint(ssl^.rmshtdn));
  456. //
  457. // Build an SSL close notify message.
  458. //
  459. dwSSPIFlags := ISC_REQ_SEQUENCE_DETECT or
  460. ISC_REQ_REPLAY_DETECT or
  461. ISC_REQ_CONFIDENTIALITY or
  462. ISC_RET_EXTENDED_ERROR or
  463. ISC_REQ_ALLOCATE_MEMORY or
  464. ISC_REQ_STREAM;
  465. OutBuffers[0].pvBuffer := nil;
  466. OutBuffers[0].BufferType := SECBUFFER_TOKEN;
  467. OutBuffers[0].cbBuffer := 0;
  468. OutBuffer.cBuffers := 1;
  469. OutBuffer.pBuffers := OutBuffers;
  470. OutBuffer.ulVersion := SECBUFFER_VERSION;
  471. Status := g_pSSPI^.InitializeSecurityContextA(
  472. @ssl^.hCreds,
  473. @ssl^.hContext,
  474. nil,
  475. dwSSPIFlags,
  476. 0,
  477. SECURITY_NATIVE_DREP,
  478. nil,
  479. 0,
  480. @ssl^.hContext,
  481. @OutBuffer,
  482. dwSSPIOutFlags,
  483. @tsExpiry);
  484. if (FAILED(Status)) then Exit(cint(ssl^.rmshtdn));
  485. // Send the close notify message to the server.
  486. if (OutBuffers[0].pvBuffer <> nil) and (OutBuffers[0].cbBuffer <> 0) then
  487. begin
  488. send(ssl^.s, OutBuffers[0].pvBuffer, OutBuffers[0].cbBuffer, 0);
  489. g_pSSPI^.FreeContextBuffer(OutBuffers[0].pvBuffer);
  490. end;
  491. // Free the security context.
  492. g_pSSPI^.DeleteSecurityContext(@ssl^.hContext);
  493. Result := cint(ssl^.rmshtdn);
  494. end;
  495. function SSL_read(ssl: PSSL; buf: PByte; num: cint): cint; cdecl;
  496. var
  497. scRet: SECURITY_STATUS;
  498. cbData: LONG;
  499. i: cint;
  500. Message: SecBufferDesc;
  501. Buffers: array [0..3] of SecBuffer;
  502. pDataBuffer: PSecBuffer;
  503. pExtraBuffer: PSecBuffer;
  504. bytes, rbytes: LONG;
  505. fQOP: ULONG = 0;
  506. begin
  507. if (ssl = nil) then Exit(SOCKET_ERROR);
  508. if (num = 0) then Exit(0);
  509. if (ssl^.cbRecDataBuf <> 0) then
  510. begin
  511. bytes := Min(num, ssl^.cbRecDataBuf);
  512. CopyMemory(buf, ssl^.pbRecDataBuf, bytes);
  513. rbytes := ssl^.cbRecDataBuf - bytes;
  514. MoveMemory(ssl^.pbRecDataBuf, ssl^.pbRecDataBuf + bytes, rbytes);
  515. ssl^.cbRecDataBuf := rbytes;
  516. Exit(bytes);
  517. end;
  518. scRet := SEC_E_OK;
  519. while (True) do
  520. begin
  521. if (0 = ssl^.cbIoBuffer) or (scRet = SEC_E_INCOMPLETE_MESSAGE) then
  522. begin
  523. if (ssl^.sbIoBuffer <= ssl^.cbIoBuffer) then
  524. begin
  525. ssl^.sbIoBuffer += 2048;
  526. ssl^.pbIoBuffer := PUCHAR(ReAllocMem(ssl^.pbIoBuffer, ssl^.sbIoBuffer));
  527. end;
  528. cbData := recv(ssl^.s, ssl^.pbIoBuffer + ssl^.cbIoBuffer, ssl^.sbIoBuffer - ssl^.cbIoBuffer, 0);
  529. if (cbData = SOCKET_ERROR) then
  530. begin
  531. Exit(SOCKET_ERROR);
  532. end
  533. else if (cbData = 0) then
  534. begin
  535. // Server disconnected.
  536. if (ssl^.cbIoBuffer <> 0) then
  537. begin
  538. scRet := SEC_E_INTERNAL_ERROR;
  539. Exit(SOCKET_ERROR);
  540. end
  541. else
  542. Exit(0);
  543. end
  544. else
  545. ssl^.cbIoBuffer += cbData;
  546. end;
  547. // Attempt to decrypt the received data.
  548. Buffers[0].pvBuffer := ssl^.pbIoBuffer;
  549. Buffers[0].cbBuffer := ssl^.cbIoBuffer;
  550. Buffers[0].BufferType := SECBUFFER_DATA;
  551. Buffers[1].BufferType := SECBUFFER_EMPTY;
  552. Buffers[2].BufferType := SECBUFFER_EMPTY;
  553. Buffers[3].BufferType := SECBUFFER_EMPTY;
  554. Message.ulVersion := SECBUFFER_VERSION;
  555. Message.cBuffers := 4;
  556. Message.pBuffers := Buffers;
  557. if (@g_pSSPI^.DecryptMessage <> nil) then
  558. scRet := g_pSSPI^.DecryptMessage(@ssl^.hContext, @Message, 0, fQOP)
  559. else
  560. scRet := DECRYPT_MESSAGE_FN(g_pSSPI^.Reserved4)(@ssl^.hContext, @Message, 0, fQOP);
  561. if (scRet = SEC_E_INCOMPLETE_MESSAGE) then
  562. begin
  563. // The input buffer contains only a fragment of an
  564. // encrypted record. Loop around and read some more
  565. // data.
  566. continue;
  567. end;
  568. // Server signaled end of session
  569. if (scRet = SEC_I_CONTEXT_EXPIRED) then
  570. begin
  571. ssl^.rmshtdn := TRUE;
  572. SSL_shutdown(ssl);
  573. Exit(0);
  574. end;
  575. if (scRet <> SEC_E_OK) and
  576. (scRet <> SEC_I_RENEGOTIATE) and
  577. (scRet <> SEC_I_CONTEXT_EXPIRED) then
  578. begin
  579. Exit(SOCKET_ERROR);
  580. end;
  581. // Locate data and (optional) extra buffers.
  582. pDataBuffer := nil;
  583. pExtraBuffer := nil;
  584. for i := 1 to 3 do
  585. begin
  586. if (pDataBuffer = nil) and (Buffers[i].BufferType = SECBUFFER_DATA) then
  587. begin
  588. pDataBuffer := @Buffers[i];
  589. end;
  590. if (pExtraBuffer = nil) and (Buffers[i].BufferType = SECBUFFER_EXTRA) then
  591. begin
  592. pExtraBuffer := @Buffers[i];
  593. end;
  594. end;
  595. // Return decrypted data.
  596. if Assigned(pDataBuffer) then
  597. begin
  598. bytes := Min(num, pDataBuffer^.cbBuffer);
  599. CopyMemory(buf, pDataBuffer^.pvBuffer, bytes);
  600. rbytes := pDataBuffer^.cbBuffer - bytes;
  601. if (rbytes > 0) then
  602. begin
  603. if (ssl^.sbRecDataBuf < rbytes) then
  604. begin
  605. ssl^.sbRecDataBuf := rbytes;
  606. ssl^.pbRecDataBuf := PUCHAR(ReAllocMem(ssl^.pbRecDataBuf, rbytes));
  607. end;
  608. CopyMemory(ssl^.pbRecDataBuf, pDataBuffer^.pvBuffer + bytes, rbytes);
  609. ssl^.cbRecDataBuf := rbytes;
  610. end;
  611. end;
  612. // Move any "extra" data to the input buffer.
  613. if Assigned(pExtraBuffer) then
  614. begin
  615. MoveMemory(ssl^.pbIoBuffer, pExtraBuffer^.pvBuffer, pExtraBuffer^.cbBuffer);
  616. ssl^.cbIoBuffer := pExtraBuffer^.cbBuffer;
  617. end
  618. else
  619. ssl^.cbIoBuffer := 0;
  620. if (pDataBuffer <> nil) and (bytes <> 0) then Exit(bytes);
  621. if (scRet = SEC_I_RENEGOTIATE) then
  622. begin
  623. // The server wants to perform another handshake
  624. // sequence.
  625. scRet := ClientHandshakeLoop(ssl, FALSE);
  626. if (scRet <> SEC_E_OK) then Exit(SOCKET_ERROR);
  627. end;
  628. end;
  629. end;
  630. function SSL_write(ssl: PSSL; const buf: PByte; num: cint): cint; cdecl;
  631. var
  632. Sizes: SecPkgContext_StreamSizes;
  633. scRet: SECURITY_STATUS;
  634. cbData: LONG;
  635. Message: SecBufferDesc;
  636. Buffers: array[0..3] of SecBuffer;
  637. pbDataBuffer: PUCHAR;
  638. pbMessage: PUCHAR;
  639. cbMessage: DWORD;
  640. sendOff: DWORD = 0;
  641. begin
  642. if (ssl = nil) then Exit(SOCKET_ERROR);
  643. FillChar(Buffers, SizeOf(Buffers), 0);
  644. scRet := g_pSSPI^.QueryContextAttributesA(@ssl^.hContext, SECPKG_ATTR_STREAM_SIZES, @Sizes);
  645. if (scRet <> SEC_E_OK) then Exit(scRet);
  646. pbDataBuffer := PUCHAR(GetMem(Sizes.cbMaximumMessage + Sizes.cbHeader + Sizes.cbTrailer));
  647. pbMessage := pbDataBuffer + Sizes.cbHeader;
  648. while (sendOff < DWORD(num)) do
  649. begin
  650. cbMessage := Min(Sizes.cbMaximumMessage, DWORD(num) - sendOff);
  651. CopyMemory(pbMessage, buf + sendOff, cbMessage);
  652. Buffers[0].pvBuffer := pbDataBuffer;
  653. Buffers[0].cbBuffer := Sizes.cbHeader;
  654. Buffers[0].BufferType := SECBUFFER_STREAM_HEADER;
  655. Buffers[1].pvBuffer := pbMessage;
  656. Buffers[1].cbBuffer := cbMessage;
  657. Buffers[1].BufferType := SECBUFFER_DATA;
  658. Buffers[2].pvBuffer := pbMessage + cbMessage;
  659. Buffers[2].cbBuffer := Sizes.cbTrailer;
  660. Buffers[2].BufferType := SECBUFFER_STREAM_TRAILER;
  661. Buffers[3].BufferType := SECBUFFER_EMPTY;
  662. Message.ulVersion := SECBUFFER_VERSION;
  663. Message.cBuffers := 4;
  664. Message.pBuffers := Buffers;
  665. if (@g_pSSPI^.EncryptMessage <> nil) then
  666. scRet := g_pSSPI^.EncryptMessage(@ssl^.hContext, 0, @Message, 0)
  667. else
  668. scRet := ENCRYPT_MESSAGE_FN(g_pSSPI^.Reserved3)(@ssl^.hContext, 0, @Message, 0);
  669. if (FAILED(scRet)) then break;
  670. // Calculate encrypted packet size
  671. cbData := Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer;
  672. // Send the encrypted data to the server.
  673. cbData := send(ssl^.s, pbDataBuffer, cbData, 0);
  674. if (cbData = SOCKET_ERROR) or (cbData = 0) then
  675. begin
  676. g_pSSPI^.DeleteSecurityContext(@ssl^.hContext);
  677. scRet := SEC_E_INTERNAL_ERROR;
  678. break;
  679. end;
  680. sendOff += cbMessage;
  681. end;
  682. FreeMem(pbDataBuffer);
  683. if scRet = SEC_E_OK then
  684. Result := num
  685. else
  686. Result := SOCKET_ERROR;
  687. end;
  688. function SSL_pending(ssl: PSSL): cint; cdecl;
  689. begin
  690. if (ssl = nil) then Exit(0);
  691. if ssl^.cbRecDataBuf > 0 then
  692. Result := ssl^.cbRecDataBuf
  693. else if ssl^.exIoBuffer then
  694. begin
  695. ssl^.exIoBuffer := False;
  696. Result := ssl^.cbIoBuffer
  697. end
  698. else
  699. Result := 0;
  700. end;
  701. function SSLv23_method(): PSSL_METHOD; cdecl;
  702. begin
  703. Result:= PSSL_METHOD(SP_PROT_SSL3 or SP_PROT_TLS1 or SP_PROT_TLS1_1);
  704. end;
  705. function SSLv2_method(): PSSL_METHOD; cdecl;
  706. begin
  707. Result := PSSL_METHOD(SP_PROT_SSL2);
  708. end;
  709. function SSLv3_method(): PSSL_METHOD; cdecl;
  710. begin
  711. Result := PSSL_METHOD(SP_PROT_SSL3);
  712. end;
  713. function TLSv1_method(): PSSL_METHOD; cdecl;
  714. begin
  715. Result := PSSL_METHOD(SP_PROT_TLS1);
  716. end;
  717. function TLSv1_1_method(): PSSL_METHOD; cdecl;
  718. begin
  719. Result := PSSL_METHOD(SP_PROT_TLS1_1);
  720. end;
  721. function TLSv1_2_method(): PSSL_METHOD; cdecl;
  722. begin
  723. Result := PSSL_METHOD(SP_PROT_TLS1_2);
  724. end;
  725. procedure SSL_CTX_set_verify(ctx: PSSL_CTX; mode: cint; func: Pointer); cdecl;
  726. begin
  727. if (ctx <> nil) then ctx^.bVerify := mode <> 0;
  728. end;
  729. function SSL_get_error (ssl: PSSL; ret: cint): cint; cdecl;
  730. begin
  731. if (ret > 0) then
  732. Result := SSL_ERROR_NONE
  733. else
  734. Result := SSL_ERROR_ZERO_RETURN;
  735. end;
  736. var
  737. lpBuffer: TMemoryBasicInformation;
  738. begin
  739. if (IsSSLloaded = False) then
  740. begin
  741. if VirtualQuery(@lpBuffer, @lpBuffer, SizeOf(lpBuffer)) = SizeOf(lpBuffer) then
  742. begin
  743. SetLength(DLLSSLName, MAX_PATH);
  744. SetLength(DLLSSLName, GetModuleFileName(THandle(lpBuffer.AllocationBase),
  745. PAnsiChar(DLLSSLName), MAX_PATH));
  746. DLLUtilName := DLLSSLName;
  747. if InitSSLInterface then
  748. SSLImplementation := TSSLOpenSSL;
  749. end;
  750. end;
  751. end.