IdSSLOpenSSLUtils.pas 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037
  1. unit IdSSLOpenSSLUtils deprecated;
  2. interface
  3. {$I IdCompilerDefines.inc}
  4. uses
  5. IdCTypes,
  6. IdSSLOpenSSLHeaders,
  7. Classes;
  8. type
  9. TIdSSLULong = packed record
  10. case Byte of
  11. 0: (B1, B2, B3, B4: Byte);
  12. 1: (W1, W2: Word);
  13. 2: (L1: Longint);
  14. 3: (C1: LongWord);
  15. end;
  16. TIdSSLEVP_MD = record
  17. Length: TIdC_UINT;
  18. MD: Array [0 .. EVP_MAX_MD_SIZE - 1] of AnsiChar;
  19. end;
  20. TIdSSLByteArray = record
  21. Length: TIdC_INT;
  22. Data: PAnsiChar;
  23. End;
  24. function LoadOpenSSLLibrary: Boolean;
  25. procedure UnLoadOpenSSLLibrary;
  26. // locking callback stuff
  27. procedure LockPasswordCB_Enter;
  28. procedure LockPasswordCB_Leave;
  29. procedure LockInfoCB_Enter;
  30. procedure LockInfoCB_Leave;
  31. procedure LockVerifyCB_Enter;
  32. procedure LockVerifyCB_Leave;
  33. //
  34. function AddMins(const DT: TDateTime; const Mins: Extended): TDateTime;
  35. function AddHrs(const DT: TDateTime; const Hrs: Extended): TDateTime;
  36. function GetLocalTime(const DT: TDateTime): TDateTime; deprecated 'Use IdGlobal.UTCTimeToLocalTime()';
  37. function IndySSL_load_client_CA_file(const AFileName: String) : PSTACK_OF_X509_NAME;
  38. function IndySSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const AFileName: String;
  39. AType: Integer): Boolean;
  40. function IndySSL_CTX_use_certificate_file(ctx: PSSL_CTX;
  41. const AFileName: String; AType: Integer): Boolean;
  42. function IndyX509_STORE_load_locations(ctx: PX509_STORE;
  43. const AFileName, APathName: String): TIdC_INT;
  44. function IndySSL_CTX_load_verify_locations(ctx: PSSL_CTX;
  45. const ACAFile, ACAPath: String): TIdC_INT;
  46. procedure DumpCert(AOut: TStrings; AX509: PX509);
  47. procedure SslLockingCallback(mode, n: TIdC_INT; Afile: PAnsiChar;
  48. line: TIdC_INT)cdecl;
  49. procedure PrepareOpenSSLLocking;
  50. {$IFNDEF WIN32_OR_WIN64}
  51. function _GetThreadID: TIdC_ULONG; cdecl;
  52. {$ENDIF}
  53. // Note that I define UCTTime as PASN1_STRING
  54. function UTCTime2DateTime(UCTTime: PASN1_UTCTIME): TDateTime;
  55. { function RSACallback(sslSocket: PSSL; e: Integer; KeyLength: Integer):PRSA; cdecl;
  56. }
  57. function LogicalAnd(A, B: Integer): Boolean;
  58. function BytesToHexString(APtr: Pointer; ALen: Integer): String;
  59. function MDAsString(const AMD: TIdSSLEVP_MD): String;
  60. procedure GetStateVars(const sslSocket: PSSL; AWhere, Aret: TIdC_INT; var VTypeStr, VMsg : String);
  61. {$IFDEF WINDOWS}
  62. {
  63. This is for some file lookup definitions for a LOOKUP method that
  64. uses Unicode filesnames instead of ASCII or UTF8. It is not meant to be portable
  65. at all.
  66. }
  67. function by_Indy_unicode_file_ctrl(ctx: PX509_LOOKUP; cmd: TIdC_INT;
  68. const argc: PAnsiChar; argl: TIdC_LONG; out ret: PAnsiChar): TIdC_INT;
  69. cdecl; forward;
  70. const
  71. Indy_x509_unicode_file_lookup: X509_LOOKUP_METHOD =
  72. (name: PAnsiChar('Load file into cache'); new_item: nil; // * new */
  73. free: nil; // * free */
  74. init: nil; // * init */
  75. shutdown: nil; // * shutdown */
  76. ctrl: by_Indy_unicode_file_ctrl; // * ctrl */
  77. get_by_subject: nil; // * get_by_subject */
  78. get_by_issuer_serial: nil; // * get_by_issuer_serial */
  79. get_by_fingerprint: nil; // * get_by_fingerprint */
  80. get_by_alias: nil // * get_by_alias */
  81. );
  82. {$ENDIF}
  83. implementation
  84. uses
  85. {$IFDEF WIN32_OR_WIN64}
  86. Windows,
  87. {$ENDIF}
  88. {$IFDEF USE_VCL_POSIX}
  89. Posix.Glue,
  90. Posix.SysTime,
  91. Posix.Time,
  92. Posix.Unistd,
  93. {$ENDIF}
  94. IdGlobal,
  95. IdGlobalProtocols,
  96. IdResourceStrings,
  97. IdResourceStringsCore,
  98. IdResourceStringsProtocols,
  99. IdThreadSafe,
  100. SyncObjs,
  101. SysUtils;
  102. var
  103. SSLIsLoaded: TIdThreadSafeBoolean = nil;
  104. LockInfoCB: TIdCriticalSection = nil;
  105. LockPassCB: TIdCriticalSection = nil;
  106. LockVerifyCB: TIdCriticalSection = nil;
  107. CallbackLockList: TThreadList = nil;
  108. procedure LockPasswordCB_Enter;
  109. begin
  110. LockPassCB.Enter;
  111. end;
  112. procedure LockPasswordCB_Leave;
  113. begin
  114. LockPassCB.Leave;
  115. end;
  116. procedure LockInfoCB_Enter;
  117. begin
  118. LockInfoCB.Enter;
  119. end;
  120. procedure LockInfoCB_Leave;
  121. begin
  122. LockInfoCB.Leave;
  123. end;
  124. procedure LockVerifyCB_Enter;
  125. begin
  126. LockVerifyCB.Enter;
  127. end;
  128. procedure LockVerifyCB_Leave;
  129. begin
  130. LockVerifyCB.Leave;
  131. end;
  132. {
  133. IMPORTANT!!!
  134. OpenSSL can not handle Unicode file names at all. On Posix systems, UTF8 File
  135. names can be used with OpenSSL. The Windows operating system does not accept
  136. UTF8 file names at all so we have our own routines that will handle Unicode
  137. filenames. Most of this section of code is based on code in the OpenSSL .DLL
  138. which is copyrighted by the OpenSSL developers. Come of it is translated into
  139. Pascal and made some modifications so that it will handle Unicode filenames.
  140. }
  141. {$IF DEFINED(WINDOWS)}
  142. function Indy_unicode_X509_load_cert_crl_file(ctx: PX509_LOOKUP; const AFileName: String;
  143. const _type: TIdC_INT): TIdC_INT; forward;
  144. function Indy_unicode_X509_load_cert_file(ctx: PX509_LOOKUP; const AFileName: String;
  145. _type: TIdC_INT): TIdC_INT; forward;
  146. function Indy_Unicode_X509_LOOKUP_file(): PX509_LOOKUP_METHOD cdecl;
  147. {$IFDEF USE_INLINE} inline; {$ENDIF}
  148. begin
  149. Result := @Indy_x509_unicode_file_lookup;
  150. end;
  151. function by_Indy_unicode_file_ctrl(ctx: PX509_LOOKUP; cmd: TIdC_INT;
  152. const argc: PAnsiChar; argl: TIdC_LONG; out ret: PAnsiChar): TIdC_INT; cdecl;
  153. var
  154. LOk: TIdC_INT;
  155. LFileName: String;
  156. begin
  157. LOk := 0;
  158. case cmd of
  159. X509_L_FILE_LOAD:
  160. begin
  161. case argl of
  162. X509_FILETYPE_DEFAULT:
  163. begin
  164. LFileName := GetEnvironmentVariable
  165. (String(X509_get_default_cert_file_env));
  166. if LFileName <> '' then begin
  167. Result := Indy_unicode_X509_load_cert_crl_file(ctx, LFileName,
  168. X509_FILETYPE_PEM);
  169. end else begin
  170. Result := Indy_unicode_X509_load_cert_crl_file(ctx,
  171. String(X509_get_default_cert_file), X509_FILETYPE_PEM);
  172. end;
  173. if Result = 0 then begin
  174. X509err(X509_F_BY_FILE_CTRL, X509_R_LOADING_DEFAULTS);
  175. end;
  176. end;
  177. X509_FILETYPE_PEM:
  178. begin
  179. // Note that typecasting an AnsiChar as a WideChar is normally a crazy
  180. // thing to do. The thing is that the OpenSSL API is based on ASCII or
  181. // UTF8, not Unicode and we are writing this just for Unicode filenames.
  182. LFileName := PWideChar(argc);
  183. LOk := Indy_unicode_X509_load_cert_crl_file(ctx, LFileName,
  184. X509_FILETYPE_PEM);
  185. end;
  186. else
  187. LFileName := PWideChar(argc);
  188. LOk := Indy_unicode_X509_load_cert_file(ctx, LFileName, TIdC_INT(argl));
  189. end;
  190. end;
  191. end;
  192. {Do it this way because 1 must be returned for success and unfortunately, some
  193. routines return the number of certificates that were loaded which could be
  194. more than 1}
  195. if LOk > 0 then begin
  196. Result := 1;
  197. end else begin
  198. Result := 0;
  199. end;
  200. end;
  201. function Indy_unicode_X509_load_cert_file(ctx: PX509_LOOKUP; const AFileName: String;
  202. _type: TIdC_INT): TIdC_INT;
  203. var
  204. LM: TMemoryStream;
  205. Lin: PBIO;
  206. LX: PX509;
  207. i: Integer;
  208. begin
  209. Result := 0;
  210. Lin := nil;
  211. LM := TMemoryStream.Create;
  212. try
  213. LM.LoadFromFile(AFileName);
  214. Lin := BIO_new_mem_buf(LM.Memory, LM.Size);
  215. if not Assigned(Lin) then begin
  216. X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_SYS_LIB);
  217. Exit;
  218. end;
  219. try
  220. case _type of
  221. X509_FILETYPE_PEM:
  222. begin
  223. repeat
  224. LX := PEM_read_bio_X509_AUX(Lin, nil, nil, nil);
  225. if not Assigned(LX) then begin
  226. if ((ERR_GET_REASON(ERR_peek_last_error())
  227. = PEM_R_NO_START_LINE) and (Result > 0)) then begin
  228. ERR_clear_error();
  229. Break;
  230. end else begin
  231. X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_PEM_LIB);
  232. // goto err;
  233. end;
  234. end;
  235. until False;
  236. end;
  237. X509_FILETYPE_ASN1:
  238. begin
  239. LX := d2i_X509_bio(Lin, nil);
  240. if not Assigned(LX) then begin
  241. X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_ASN1_LIB);
  242. // goto err;
  243. end else begin
  244. i := X509_STORE_add_cert(ctx^.store_ctx, LX);
  245. if i <> 0 then begin
  246. Result := i;
  247. end;
  248. end;
  249. end;
  250. else
  251. X509err(X509_F_X509_LOAD_CERT_FILE, X509_R_BAD_X509_FILETYPE);
  252. // goto err;
  253. end;
  254. finally
  255. BIO_free(Lin);
  256. end;
  257. finally
  258. LM.Free;
  259. end;
  260. end;
  261. function Indy_unicode_X509_load_cert_crl_file(ctx: PX509_LOOKUP; const AFileName: String;
  262. const _type: TIdC_INT): TIdC_INT;
  263. var
  264. LM: TMemoryStream;
  265. Linf: PSTACK_OF_X509_INFO;
  266. Litmp: PX509_INFO;
  267. Lin: PBIO;
  268. i: Integer;
  269. begin
  270. Result := 0;
  271. Linf := nil;
  272. Lin := nil;
  273. if _type <> X509_FILETYPE_PEM then begin
  274. Result := Indy_unicode_X509_load_cert_file(ctx, AFileName, _type);
  275. Exit;
  276. end;
  277. try
  278. LM := TMemoryStream.Create;
  279. try
  280. LM.LoadFromFile(AFileName);
  281. Lin := BIO_new_mem_buf(LM.Memory, LM.Size);
  282. if not Assigned(Lin) then begin
  283. X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_SYS_LIB);
  284. end else begin
  285. try
  286. Linf := PEM_X509_INFO_read_bio(Lin, nil, nil, nil);
  287. finally
  288. BIO_free(Lin);
  289. end;
  290. end;
  291. finally
  292. LM.Free;
  293. end;
  294. except
  295. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  296. // Follow the OpenSSL .DLL Error conventions.
  297. X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_SYS_LIB);
  298. Exit;
  299. end;
  300. if not Assigned(Linf) then begin
  301. X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_PEM_LIB);
  302. Exit;
  303. end;
  304. try
  305. for i := 0 to sk_X509_INFO_num(Linf) - 1 do begin
  306. Litmp := sk_X509_INFO_value(Linf, i);
  307. if Assigned(Litmp^.x509) then begin
  308. X509_STORE_add_cert(ctx^.store_ctx, Litmp^.x509);
  309. Inc(Result);
  310. end;
  311. if Assigned(Litmp^.crl) then begin
  312. X509_STORE_add_crl(ctx^.store_ctx, Litmp^.crl);
  313. Inc(Result);
  314. end;
  315. end;
  316. finally
  317. sk_X509_INFO_pop_free(Linf, @X509_INFO_free);
  318. end;
  319. end;
  320. procedure IndySSL_load_client_CA_file_err(var VRes: PSTACK_OF_X509_NAME);
  321. {$IFDEF USE_INLINE} inline; {$ENDIF}
  322. begin
  323. if Assigned(VRes) then begin
  324. sk_X509_NAME_pop_free(VRes, @X509_NAME_free);
  325. VRes := nil;
  326. end;
  327. end;
  328. function IndySSL_load_client_CA_file(const AFileName: String): PSTACK_OF_X509_NAME;
  329. var
  330. LM: TMemoryStream;
  331. LB: PBIO;
  332. Lsk: PSTACK_OF_X509_NAME;
  333. LX: PX509;
  334. LXN, LXNDup: PX509_NAME;
  335. begin
  336. Result := nil;
  337. LX := nil;
  338. Lsk := sk_X509_NAME_new(nil); // (xname_cmp);
  339. if Assigned(Lsk) then begin
  340. try
  341. LM := TMemoryStream.Create;
  342. try
  343. LM.LoadFromFile(AFileName);
  344. LB := BIO_new_mem_buf(LM.Memory, LM.Size);
  345. if Assigned(LB) then begin
  346. try
  347. while (PEM_read_bio_X509(LB, @LX, nil, nil) <> nil) do begin
  348. try
  349. if not Assigned(Result) then begin
  350. Result := sk_X509_NAME_new_null;
  351. // RLebeau: exit here if not Assigned??
  352. if not Assigned(Result) then begin
  353. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE);
  354. end;
  355. end;
  356. LXN := X509_get_subject_name(LX);
  357. if not Assigned(LXN) then begin
  358. // error
  359. IndySSL_load_client_CA_file_err(Result);
  360. // RLebeau: exit here??
  361. // goto err;
  362. end;
  363. // * check for duplicates */
  364. LXNDup := X509_NAME_dup(LXN);
  365. if not Assigned(LXNDup) then begin
  366. // error
  367. IndySSL_load_client_CA_file_err(Result);
  368. // RLebeau: exit here??
  369. // goto err;
  370. end;
  371. if (sk_X509_NAME_find(Lsk, LXNDup) >= 0) then begin
  372. X509_NAME_free(LXNDup);
  373. end else begin
  374. sk_X509_NAME_push(Result, LXNDup);
  375. end;
  376. finally
  377. X509_free(LX);
  378. end;
  379. end;
  380. finally
  381. BIO_free(LB);
  382. end;
  383. end else begin
  384. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE);
  385. end;
  386. finally
  387. LM.Free;
  388. end;
  389. finally
  390. sk_X509_NAME_free(Lsk);
  391. end;
  392. end else begin
  393. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE);
  394. end;
  395. if Assigned(Result) then begin
  396. ERR_clear_error;
  397. end;
  398. end;
  399. function IndySSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const AFileName: String;
  400. AType: Integer): Boolean;
  401. var
  402. LM: TMemoryStream;
  403. B: PBIO;
  404. LKey: PEVP_PKEY;
  405. j: TIdC_INT;
  406. begin
  407. Result := False;
  408. LM := TMemoryStream.Create;
  409. try
  410. LM.LoadFromFile(AFileName);
  411. B := BIO_new_mem_buf(LM.Memory, LM.Size);
  412. if Assigned(B) then begin
  413. try
  414. LKey := nil;
  415. case AType of
  416. SSL_FILETYPE_PEM:
  417. begin
  418. j := ERR_R_PEM_LIB;
  419. LKey := PEM_read_bio_PrivateKey(B, nil,
  420. ctx^.default_passwd_callback,
  421. ctx^.default_passwd_callback_userdata);
  422. end;
  423. SSL_FILETYPE_ASN1:
  424. begin
  425. j := ERR_R_ASN1_LIB;
  426. LKey := d2i_PrivateKey_bio(B, nil);
  427. end;
  428. else
  429. j := SSL_R_BAD_SSL_FILETYPE;
  430. end;
  431. if Assigned(LKey) then begin
  432. try
  433. Result := SSL_CTX_use_PrivateKey(ctx, LKey) > 0;
  434. finally
  435. EVP_PKEY_free(LKey);
  436. end;
  437. end else begin
  438. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, j);
  439. end;
  440. finally
  441. BIO_free(B);
  442. end;
  443. end else begin
  444. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB);
  445. end;
  446. finally
  447. LM.Free;
  448. end;
  449. end;
  450. function IndySSL_CTX_use_certificate_file(ctx: PSSL_CTX;
  451. const AFileName: String; AType: Integer): Boolean;
  452. var
  453. LM: TMemoryStream;
  454. B: PBIO;
  455. LX: PX509;
  456. j: TIdC_INT;
  457. begin
  458. Result := False;
  459. LM := TMemoryStream.Create;
  460. try
  461. LM.LoadFromFile(AFileName);
  462. B := BIO_new_mem_buf(LM.Memory, LM.Size);
  463. if Assigned(B) then begin
  464. try
  465. LX := nil;
  466. case AType of
  467. SSL_FILETYPE_ASN1:
  468. begin
  469. j := ERR_R_ASN1_LIB;
  470. LX := d2i_X509_bio(B, nil);
  471. end;
  472. SSL_FILETYPE_PEM:
  473. begin
  474. j := ERR_R_PEM_LIB;
  475. LX := PEM_read_bio_X509(B, nil, ctx^.default_passwd_callback,
  476. ctx^.default_passwd_callback_userdata);
  477. end
  478. else
  479. j := SSL_R_BAD_SSL_FILETYPE;
  480. end;
  481. if Assigned(LX) then begin
  482. try
  483. Result := SSL_CTX_use_certificate(ctx, LX) > 0;
  484. finally
  485. X509_free(LX);
  486. end;
  487. end else begin
  488. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, j);
  489. end;
  490. finally
  491. BIO_free(B);
  492. end;
  493. end else begin
  494. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB);
  495. end;
  496. finally
  497. LM.Free;
  498. end;
  499. end;
  500. function IndyX509_STORE_load_locations(ctx: PX509_STORE;
  501. const AFileName, APathName: String): TIdC_INT;
  502. var
  503. lookup: PX509_LOOKUP;
  504. begin
  505. Result := 0;
  506. if AFileName <> '' then begin
  507. lookup := X509_STORE_add_lookup(ctx, Indy_Unicode_X509_LOOKUP_file);
  508. if Assigned(lookup) then begin
  509. if (X509_LOOKUP_load_file(lookup, PAnsiChar(@AFileName[1]),
  510. X509_FILETYPE_PEM) <> 1) then begin
  511. exit;
  512. end;
  513. Result := 1;
  514. end else begin
  515. exit;
  516. end;
  517. end;
  518. { To do: Figure out how to do the hash dir lookup with Unicode. }
  519. if APathName <> '' then begin
  520. Result := X509_STORE_load_locations(ctx, nil, PAnsiChar(AnsiString(APathName)));
  521. end;
  522. end;
  523. function IndySSL_CTX_load_verify_locations(ctx: PSSL_CTX;
  524. const ACAFile, ACAPath: String): TIdC_INT;
  525. {$IFDEF USE_INLINE} inline; {$ENDIF}
  526. begin
  527. Result := IndyX509_STORE_load_locations(ctx^.cert_store, ACAFile, ACAPath);
  528. end;
  529. {$ELSEIF DEFINED(UNIX)}
  530. function IndySSL_load_client_CA_file(const AFileName: String) : PSTACK_OF_X509_NAME;
  531. begin
  532. Result := SSL_load_client_CA_file(PAnsiChar(UTF8String(AFileName)));
  533. end;
  534. function IndySSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const AFileName: String;
  535. AType: Integer): Boolean;
  536. {$IFDEF USE_INLINE} inline; {$ENDIF}
  537. begin
  538. Result := SSL_CTX_use_PrivateKey_file(ctx, PAnsiChar(UTF8String(AFileName)),
  539. AType) > 0;
  540. end;
  541. function IndySSL_CTX_use_certificate_file(ctx: PSSL_CTX;
  542. const AFileName: String; AType: Integer): Boolean;
  543. {$IFDEF USE_INLINE} inline; {$ENDIF}
  544. begin
  545. Result := SSL_CTX_use_certificate_file(ctx, PAnsiChar(UTF8String(AFileName)),
  546. AType) > 0;
  547. end;
  548. function IndyX509_STORE_load_locations(ctx: PX509_STORE;
  549. const AFileName, APathName: String): TIdC_INT;
  550. {$IFDEF USE_INLINE} inline; {$ENDIF}
  551. begin
  552. // RLebeau 4/18/2010: X509_STORE_load_locations() expects nil pointers
  553. // for unused values, but casting a string directly to a PAnsiChar
  554. // always produces a non-nil pointer, which causes X509_STORE_load_locations()
  555. // to fail. Need to cast the string to an intermediate Pointer so the
  556. // PAnsiChar cast is applied to the raw data and thus can be nil...
  557. //
  558. Result := X509_STORE_load_locations(ctx,
  559. PAnsiChar(Pointer(UTF8String(AFileName))),
  560. PAnsiChar(Pointer(UTF8String(APathName))));
  561. end;
  562. function IndySSL_CTX_load_verify_locations(ctx: PSSL_CTX;
  563. const ACAFile, ACAPath: String): TIdC_INT;
  564. {$IFDEF USE_INLINE} inline; {$ENDIF}
  565. begin
  566. Result := IndyX509_STORE_load_locations(ctx^.cert_store, ACAFile, ACAPath);
  567. end;
  568. {$IFEND}
  569. function AddMins(const DT: TDateTime; const Mins: Extended): TDateTime;
  570. {$IFDEF USE_INLINE} inline; {$ENDIF}
  571. begin
  572. Result := DT + Mins / (60 * 24)
  573. end;
  574. function AddHrs(const DT: TDateTime; const Hrs: Extended): TDateTime;
  575. {$IFDEF USE_INLINE} inline; {$ENDIF}
  576. begin
  577. Result := DT + Hrs / 24.0;
  578. end;
  579. function GetLocalTime(const DT: TDateTime): TDateTime;
  580. {$IFDEF USE_INLINE} inline; {$ENDIF}
  581. begin
  582. Result := UTCTimeToLocalTime(DT);
  583. end;
  584. {$IFDEF OPENSSL_SET_MEMORY_FUNCS}
  585. function IdMalloc(num: Cardinal): Pointer cdecl;
  586. begin
  587. Result := AllocMem(num);
  588. end;
  589. function IdRealloc(addr: Pointer; num: Cardinal): Pointer cdecl;
  590. begin
  591. Result := addr;
  592. ReallocMem(Result, num);
  593. end;
  594. procedure IdFree(addr: Pointer)cdecl;
  595. begin
  596. FreeMem(addr);
  597. end;
  598. procedure IdSslCryptoMallocInit;
  599. // replaces the actual alloc routines
  600. // this is useful if you are using a memory manager that can report on leaks
  601. // at shutdown time.
  602. var
  603. r: Integer;
  604. begin
  605. r := CRYPTO_set_mem_functions(@IdMalloc, @IdRealloc, @IdFree);
  606. Assert(r <> 0);
  607. end;
  608. {$ENDIF}
  609. {$IFNDEF OPENSSL_NO_BIO}
  610. procedure DumpCert(AOut: TStrings; AX509: PX509);
  611. {$IFDEF USE_INLINE} inline; {$ENDIF}
  612. var
  613. LMem: PBIO;
  614. LLen : TIdC_INT;
  615. LBufPtr : Pointer;
  616. begin
  617. if Assigned(X509_print) then begin
  618. LMem := BIO_new(BIO_s_mem);
  619. try
  620. X509_print(LMem, AX509);
  621. LLen := BIO_get_mem_data( LMem, LBufPtr);
  622. if (LLen > 0) and Assigned(LBufPtr) then begin
  623. {
  624. We could have used RawToBytes() but that would have made a copy of the
  625. output buffer.
  626. }
  627. AOut.Text := IndyTextEncoding_UTF8.GetString(PByte(LBufPtr), LLen);
  628. end;
  629. finally
  630. if Assigned(LMem) then begin
  631. BIO_free(LMem);
  632. end;
  633. end;
  634. end;
  635. end;
  636. {$ELSE}
  637. procedure DumpCert(AOut: TStrings; AX509: PX509);
  638. begin
  639. end;
  640. {$ENDIF}
  641. {$IFNDEF WIN32_OR_WIN64}
  642. procedure _threadid_func(id : PCRYPTO_THREADID) cdecl;
  643. begin
  644. if Assigned(CRYPTO_THREADID_set_numeric) then begin
  645. CRYPTO_THREADID_set_numeric(id, TIdC_ULONG(CurrentThreadId));
  646. end;
  647. end;
  648. function _GetThreadID: TIdC_ULONG; cdecl;
  649. begin
  650. // TODO: Verify how well this will work with fibers potentially running from
  651. // thread to thread or many on the same thread.
  652. Result := TIdC_ULONG(CurrentThreadId);
  653. end;
  654. {$ENDIF}
  655. function LoadOpenSSLLibrary: Boolean;
  656. begin
  657. Assert(SSLIsLoaded <> nil);
  658. SSLIsLoaded.Lock;
  659. try
  660. if SSLIsLoaded.Value then begin
  661. Result := True;
  662. exit;
  663. end;
  664. Result := IdSSLOpenSSLHeaders.Load;
  665. if not Result then begin
  666. exit;
  667. end;
  668. {$IFDEF OPENSSL_SET_MEMORY_FUNCS}
  669. // has to be done before anything that uses memory
  670. IdSslCryptoMallocInit;
  671. {$ENDIF}
  672. // required eg to encrypt a private key when writing
  673. OpenSSL_add_all_ciphers;
  674. OpenSSL_add_all_digests;
  675. InitializeRandom;
  676. // IdSslRandScreen;
  677. SSL_load_error_strings;
  678. // Successful loading if true
  679. Result := SSLeay_add_ssl_algorithms > 0;
  680. if not Result then begin
  681. exit;
  682. end;
  683. // Create locking structures, we need them for callback routines
  684. Assert(LockInfoCB = nil);
  685. LockInfoCB := TIdCriticalSection.Create;
  686. LockPassCB := TIdCriticalSection.Create;
  687. LockVerifyCB := TIdCriticalSection.Create;
  688. // Handle internal OpenSSL locking
  689. CallbackLockList := TThreadList.Create;
  690. PrepareOpenSSLLocking;
  691. CRYPTO_set_locking_callback(SslLockingCallback);
  692. {$IFNDEF WIN32_OR_WIN64}
  693. if Assigned(CRYPTO_THREADID_set_callback) then begin
  694. CRYPTO_THREADID_set_callback( _threadid_func );
  695. end else begin
  696. CRYPTO_set_id_callback(_GetThreadID);
  697. end;
  698. {$ENDIF}
  699. SSLIsLoaded.Value := True;
  700. Result := True;
  701. finally
  702. SSLIsLoaded.Unlock;
  703. end;
  704. end;
  705. procedure UnLoadOpenSSLLibrary;
  706. // allow the user to call unload directly?
  707. // will then need to implement reference count
  708. var
  709. i: Integer;
  710. begin
  711. // ssl was never loaded
  712. if LockInfoCB = nil then begin
  713. exit;
  714. end;
  715. CRYPTO_set_locking_callback(nil);
  716. IdSSLOpenSSLHeaders.Unload;
  717. FreeAndNil(LockInfoCB);
  718. FreeAndNil(LockPassCB);
  719. FreeAndNil(LockVerifyCB);
  720. if Assigned(CallbackLockList) then begin
  721. with CallbackLockList.LockList do
  722. try
  723. for i := 0 to Count - 1 do begin
  724. TObject(Items[i]).free;
  725. end;
  726. Clear;
  727. finally
  728. CallbackLockList.UnlockList;
  729. end;
  730. FreeAndNil(CallbackLockList);
  731. end;
  732. SSLIsLoaded.Value := False;
  733. end;
  734. procedure SslLockingCallback(mode, n: TIdC_INT; Afile: PAnsiChar;
  735. line: TIdC_INT)cdecl;
  736. var
  737. Lock: TIdCriticalSection;
  738. begin
  739. Assert(CallbackLockList <> nil);
  740. Lock := nil;
  741. with CallbackLockList.LockList do
  742. try
  743. if n < Count then begin
  744. Lock := TIdCriticalSection(Items[n]);
  745. end;
  746. finally
  747. CallbackLockList.UnlockList;
  748. end;
  749. Assert(Lock <> nil);
  750. if (mode and CRYPTO_LOCK) = CRYPTO_LOCK then begin
  751. Lock.Acquire;
  752. end else begin
  753. Lock.Release;
  754. end;
  755. end;
  756. procedure PrepareOpenSSLLocking;
  757. var
  758. i, cnt: Integer;
  759. Lock: TIdCriticalSection;
  760. begin
  761. with CallbackLockList.LockList do
  762. try
  763. cnt := _CRYPTO_num_locks;
  764. for i := 0 to cnt - 1 do begin
  765. Lock := TIdCriticalSection.Create;
  766. try
  767. Add(Lock);
  768. except
  769. Lock.free;
  770. raise ;
  771. end;
  772. end;
  773. finally
  774. CallbackLockList.UnlockList;
  775. end;
  776. end;
  777. // Note that I define UCTTime as PASN1_STRING
  778. function UTCTime2DateTime(UCTTime: PASN1_UTCTIME): TDateTime;
  779. {$IFDEF USE_INLINE} inline; {$ENDIF}
  780. var
  781. year: Word;
  782. month: Word;
  783. day: Word;
  784. hour: Word;
  785. min: Word;
  786. sec: Word;
  787. tz_h: Integer;
  788. tz_m: Integer;
  789. begin
  790. Result := 0;
  791. if UTC_Time_Decode(UCTTime, year, month, day, hour, min, sec, tz_h, tz_m) > 0 then begin
  792. Result := EncodeDate(year, month, day) + EncodeTime(hour, min, sec, 0);
  793. AddMins(Result, tz_m);
  794. AddHrs(Result, tz_h);
  795. Result := GetLocalTime(Result);
  796. end;
  797. end;
  798. {
  799. function RSACallback(sslSocket: PSSL; e: Integer; KeyLength: Integer):PRSA; cdecl;
  800. const
  801. RSA: PRSA = nil;
  802. var
  803. SSLSocket: TSSLWSocket;
  804. IdSSLSocket: TIdSSLSocket;
  805. begin
  806. IdSSLSocket := TIdSSLSocket(IdSslGetAppData(sslSocket));
  807. if Assigned(IdSSLSocket) then begin
  808. IdSSLSocket.TriggerSSLRSACallback(KeyLength);
  809. end;
  810. Result := RSA_generate_key(KeyLength, RSA_F4, @RSAProgressCallback, ssl);
  811. end;
  812. }
  813. function LogicalAnd(A, B: Integer): Boolean;
  814. {$IFDEF USE_INLINE} inline; {$ENDIF}
  815. begin
  816. Result := (A and B) = B;
  817. end;
  818. function BytesToHexString(APtr: Pointer; ALen: Integer): String;
  819. {$IFDEF USE_INLINE} inline; {$ENDIF}
  820. var
  821. i: PtrInt;
  822. LPtr: PByte;
  823. begin
  824. Result := '';
  825. LPtr := PByte(APtr);
  826. for i := 0 to (ALen - 1) do begin
  827. if i <> 0 then begin
  828. Result := Result + ':'; { Do not Localize }
  829. end;
  830. Result := Result + IndyFormat('%.2x', [LPtr^]);
  831. Inc(LPtr);
  832. end;
  833. end;
  834. function MDAsString(const AMD: TIdSSLEVP_MD): String;
  835. {$IFDEF USE_INLINE} inline; {$ENDIF}
  836. var
  837. i: Integer;
  838. begin
  839. Result := '';
  840. for i := 0 to AMD.Length - 1 do begin
  841. if i <> 0 then begin
  842. Result := Result + ':'; { Do not Localize }
  843. end;
  844. Result := Result + IndyFormat('%.2x', [Byte(AMD.MD[i])]);
  845. { do not localize }
  846. end;
  847. end;
  848. procedure GetStateVars(const sslSocket: PSSL; AWhere, Aret: TIdC_INT; var VTypeStr, VMsg : String);
  849. {$IFDEF USE_INLINE}inline;{$ENDIF}
  850. begin
  851. case AWhere of
  852. SSL_CB_ALERT :
  853. begin
  854. VTypeStr := IndyFormat( RSOSSLAlert,[SSL_alert_type_string_long(Aret)]);
  855. VMsg := String(SSL_alert_type_string_long(Aret));
  856. end;
  857. SSL_CB_READ_ALERT :
  858. begin
  859. VTypeStr := IndyFormat(RSOSSLReadAlert,[SSL_alert_type_string_long(Aret)]);
  860. VMsg := String( SSL_alert_desc_string_long(Aret));
  861. end;
  862. SSL_CB_WRITE_ALERT :
  863. begin
  864. VTypeStr := IndyFormat(RSOSSLWriteAlert,[SSL_alert_type_string_long(Aret)]);
  865. VMsg := String( SSL_alert_desc_string_long(Aret));
  866. end;
  867. SSL_CB_ACCEPT_LOOP :
  868. begin
  869. VTypeStr := RSOSSLAcceptLoop;
  870. VMsg := String( SSL_state_string_long(sslSocket));
  871. end;
  872. SSL_CB_ACCEPT_EXIT :
  873. begin
  874. if ARet < 0 then begin
  875. VTypeStr := RSOSSLAcceptError;
  876. end else begin
  877. if ARet = 0 then begin
  878. VTypeStr := RSOSSLAcceptFailed;
  879. end else begin
  880. VTypeStr := RSOSSLAcceptExit;
  881. end;
  882. end;
  883. VMsg := String( SSL_state_string_long(sslSocket) );
  884. end;
  885. SSL_CB_CONNECT_LOOP :
  886. begin
  887. VTypeStr := RSOSSLConnectLoop;
  888. VMsg := String( SSL_state_string_long(sslSocket) );
  889. end;
  890. SSL_CB_CONNECT_EXIT :
  891. begin
  892. if ARet < 0 then begin
  893. VTypeStr := RSOSSLConnectError;
  894. end else begin
  895. if ARet = 0 then begin
  896. VTypeStr := RSOSSLConnectFailed
  897. end else begin
  898. VTypeStr := RSOSSLConnectExit;
  899. end;
  900. end;
  901. VMsg := String( SSL_state_string_long(sslSocket) );
  902. end;
  903. SSL_CB_HANDSHAKE_START :
  904. begin
  905. VTypeStr := RSOSSLHandshakeStart;
  906. VMsg := String( SSL_state_string_long(sslSocket) );
  907. end;
  908. SSL_CB_HANDSHAKE_DONE :
  909. begin
  910. VTypeStr := RSOSSLHandshakeDone;
  911. VMsg := String( SSL_state_string_long(sslSocket) );
  912. end;
  913. end;
  914. {var LW : TIdC_INT;
  915. begin
  916. VMsg := '';
  917. LW := Awhere and (not SSL_ST_MASK);
  918. if (LW and SSL_ST_CONNECT) > 0 then begin
  919. VWhereStr := 'SSL_connect:';
  920. end else begin
  921. if (LW and SSL_ST_ACCEPT) > 0 then begin
  922. VWhereStr := ' SSL_accept:';
  923. end else begin
  924. VWhereStr := ' undefined:';
  925. end;
  926. end;
  927. // IdSslStateStringLong
  928. if (Awhere and SSL_CB_LOOP) > 0 then begin
  929. VMsg := IdSslStateStringLong(sslSocket);
  930. end else begin
  931. if (Awhere and SSL_CB_ALERT) > 0 then begin
  932. if (Awhere and SSL_CB_READ > 0) then begin
  933. VWhereStr := VWhereStr + ' read:'+ IdSslAlertTypeStringLong(Aret);
  934. end else begin
  935. VWhereStr := VWhereStr + 'write:'+ IdSslAlertTypeStringLong(Aret);
  936. end;;
  937. VMsg := IdSslAlertDescStringLong(Aret);
  938. end else begin
  939. if (Awhere and SSL_CB_EXIT) > 0 then begin
  940. if ARet = 0 then begin
  941. VWhereStr := VWhereStr +'failed';
  942. VMsg := IdSslStateStringLong(sslSocket);
  943. end else begin
  944. if ARet < 0 then begin
  945. VWhereStr := VWhereStr +'error';
  946. VMsg := IdSslStateStringLong(sslSocket);
  947. end;
  948. end;
  949. end;
  950. end;
  951. end; }
  952. end;
  953. initialization
  954. Assert(SSLIsLoaded=nil);
  955. SSLIsLoaded := TIdThreadSafeBoolean.Create;
  956. finalization
  957. UnLoadOpenSSLLibrary;
  958. //free the lock last as unload makes calls that use it
  959. FreeAndNil(SSLIsLoaded);
  960. end.