IdSSLOpenSSLUtils.pas 31 KB

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