IdSSLOpenSSL.pas 132 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. Rev 1.40 03/11/2009 09:04:00 AWinkelsdorf
  18. Implemented fix for Vista+ SSL_Read and SSL_Write to allow connection
  19. timeout.
  20. Rev 1.39 16/02/2005 23:26:08 CCostelloe
  21. Changed OnVerifyPeer. Breaks existing implementation of OnVerifyPeer. See
  22. long comment near top of file.
  23. Rev 1.38 1/31/05 6:02:28 PM RLebeau
  24. Updated _GetThreadId() callback to reflect changes in IdGlobal unit
  25. Rev 1.37 7/27/2004 1:54:26 AM JPMugaas
  26. Now should use the Intercept property for sends.
  27. Rev 1.36 2004-05-18 21:38:36 Mattias
  28. Fixed unload bug
  29. Rev 1.35 2004-05-07 16:34:26 Mattias
  30. Implemented OpenSSL locking callbacks
  31. Rev 1.34 27/04/2004 9:38:48 HHariri
  32. Added compiler directive so it works in BCB
  33. Rev 1.33 4/26/2004 12:41:10 AM BGooijen
  34. Fixed WriteDirect
  35. Rev 1.32 2004.04.08 10:55:30 PM czhower
  36. IOHandler changes.
  37. Rev 1.31 3/7/2004 9:02:58 PM JPMugaas
  38. Fixed compiler warning about visibility.
  39. Rev 1.30 2004.03.07 11:46:40 AM czhower
  40. Flushbuffer fix + other minor ones found
  41. Rev 1.29 2/7/2004 5:50:50 AM JPMugaas
  42. Fixed Copyright.
  43. Rev 1.28 2/6/2004 3:45:56 PM JPMugaas
  44. Only a start on NET porting. This is not finished and will not compile on
  45. DotNET>
  46. Rev 1.27 2004.02.03 5:44:24 PM czhower
  47. Name changes
  48. Rev 1.26 1/21/2004 4:03:48 PM JPMugaas
  49. InitComponent
  50. Rev 1.25 1/14/2004 11:39:10 AM JPMugaas
  51. Server IOHandler now works. Accept was commented out.
  52. Rev 1.24 2003.11.29 10:19:28 AM czhower
  53. Updated for core change to InputBuffer.
  54. Rev 1.23 10/21/2003 10:09:14 AM JPMugaas
  55. Intercept enabled.
  56. Rev 1.22 10/21/2003 09:41:38 AM JPMugaas
  57. Updated for new API. Verified with TIdFTP with active and passive transfers
  58. as well as clear and protected data channels.
  59. Rev 1.21 10/21/2003 07:32:38 AM JPMugaas
  60. Checked in what I have. Porting still continues.
  61. Rev 1.20 10/17/2003 1:08:08 AM DSiders
  62. Added localization comments.
  63. Rev 1.19 2003.10.12 6:36:44 PM czhower
  64. Now compiles.
  65. Rev 1.18 9/19/2003 11:24:58 AM JPMugaas
  66. Should compile.
  67. Rev 1.17 9/18/2003 10:20:32 AM JPMugaas
  68. Updated for new API.
  69. Rev 1.16 2003.07.16 3:26:52 PM czhower
  70. Fixed for a core change.
  71. Rev 1.15 6/30/2003 1:52:22 PM BGooijen
  72. Changed for new buffer interface
  73. Rev 1.14 6/29/2003 5:42:02 PM BGooijen
  74. fixed problem in TIdSSLIOHandlerSocketOpenSSL.SetPassThrough that Henrick
  75. Hellstrom reported
  76. Rev 1.13 5/7/2003 7:13:00 PM BGooijen
  77. changed Connected to BindingAllocated in ReadFromSource
  78. Rev 1.12 3/30/2003 12:16:40 AM BGooijen
  79. bugfixed+ added MakeFTPSvrPort/MakeFTPSvrPasv
  80. Rev 1.11 3/14/2003 06:56:08 PM JPMugaas
  81. Added a clone method to the SSLContext.
  82. Rev 1.10 3/14/2003 05:29:10 PM JPMugaas
  83. Change to prevent an AV when shutting down the FTP Server.
  84. Rev 1.9 3/14/2003 10:00:38 PM BGooijen
  85. Removed TIdServerIOHandlerSSLBase.PeerPassthrough, the ssl is now enabled in
  86. the server-protocol-files
  87. Rev 1.8 3/13/2003 11:55:38 AM JPMugaas
  88. Updated registration framework to give more information.
  89. Rev 1.7 3/13/2003 11:07:14 AM JPMugaas
  90. OpenSSL classes renamed.
  91. Rev 1.6 3/13/2003 10:28:16 AM JPMugaas
  92. Forgot the reegistration - OOPS!!!
  93. Rev 1.5 3/13/2003 09:49:42 AM JPMugaas
  94. Now uses an abstract SSL base class instead of OpenSSL so 3rd-party vendors
  95. can plug-in their products.
  96. Rev 1.4 3/13/2003 10:20:08 AM BGooijen
  97. Server side fibers
  98. Rev 1.3 2003.02.25 3:56:22 AM czhower
  99. Rev 1.2 2/5/2003 10:27:46 PM BGooijen
  100. Fixed bug in OpenEncodedConnection
  101. Rev 1.1 2/4/2003 6:31:22 PM BGooijen
  102. Fixed for Indy 10
  103. Rev 1.0 11/13/2002 08:01:24 AM JPMugaas
  104. }
  105. unit IdSSLOpenSSL;
  106. {
  107. Author: Gregor Ibic ([email protected])
  108. Copyright: (c) Gregor Ibic, Intelicom d.o.o and Indy Working Group.
  109. }
  110. {
  111. Indy OpenSSL now uses the standard OpenSSL libraries
  112. for pre-compiled win32 dlls, see:
  113. http://www.openssl.org/related/binaries.html
  114. recommended v0.9.8a or later
  115. }
  116. {
  117. Important information concerning OnVerifyPeer:
  118. Rev 1.39 of February 2005 deliberately broke the OnVerifyPeer interface,
  119. which (obviously?) only affects programs that implemented that callback
  120. as part of the SSL negotiation. Note that you really should always
  121. implement OnVerifyPeer, otherwise the certificate of the peer you are
  122. connecting to is NOT checked to ensure it is valid.
  123. Prior to this, if the SSL library detected a problem with a certificate
  124. or the Depth was insufficient (i.e. the "Ok" parameter in VerifyCallback
  125. is 0 / FALSE), then irrespective of whether your OnVerifyPeer returned True
  126. or False, the SSL connection would be deliberately failed.
  127. This created a problem in that even if there was only a very minor
  128. problem with one of the certificates in the chain (OnVerifyPeer is called
  129. once for each certificate in the certificate chain), which the user may
  130. have been happy to accept, the SSL negotiation would be failed. However,
  131. changing the code to allow the SSL connection when a user returned True
  132. for OnVerifyPeer would have meant that existing code which depended on
  133. automatic rejection of invalid certificates would then be accepting
  134. invalid certificates, which would have been an unacceptable security
  135. change.
  136. Consequently, OnVerifyPeer was changed to deliberately break existing code
  137. by adding an AOk parameter. To preserve the previous functionality, your
  138. OnVerifyPeer event should do "Result := AOk;". If you wish to consider
  139. accepting certificates that the SSL library has considered invalid, then
  140. in your OnVerifyPeer, make sure you satisfy yourself that the certificate
  141. really is valid and then set Result to True. In reality, in addition to
  142. checking AOk, you should always implement code that ensures you are only
  143. accepting certificates which are valid (at least from your point of view).
  144. Ciaran Costelloe, [email protected]
  145. }
  146. {
  147. RLebeau 1/12/2011: Breaking OnVerifyPeer event again, this time to add an
  148. additional AError parameter (patch courtesy of "jvlad", [email protected]).
  149. This helps user code distinquish between Self-signed and invalid certificates.
  150. }
  151. interface
  152. {$I IdCompilerDefines.inc}
  153. {$IFNDEF USE_OPENSSL}
  154. {$message error Should not compile if USE_OPENSSL is not defined!!!}
  155. {$ENDIF}
  156. {$TYPEDADDRESS OFF}
  157. uses
  158. //facilitate inlining only.
  159. {$IFDEF WINDOWS}
  160. Windows,
  161. {$ENDIF}
  162. Classes,
  163. IdBuffer,
  164. IdCTypes,
  165. IdGlobal,
  166. IdException,
  167. IdStackConsts,
  168. IdSocketHandle,
  169. IdSSLOpenSSLHeaders,
  170. IdComponent,
  171. IdIOHandler,
  172. IdGlobalProtocols,
  173. IdTCPServer,
  174. IdThread,
  175. IdTCPConnection,
  176. IdIntercept,
  177. IdIOHandlerSocket,
  178. IdSSL,
  179. IdSocks,
  180. IdScheduler,
  181. IdYarn;
  182. type
  183. TIdSSLVersion = (sslvSSLv2, sslvSSLv23, sslvSSLv3, sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2, sslvTLSv1_3);
  184. TIdSSLVersions = set of TIdSSLVersion;
  185. TIdSSLMode = (sslmUnassigned, sslmClient, sslmServer, sslmBoth);
  186. TIdSSLVerifyMode = (sslvrfPeer, sslvrfFailIfNoPeerCert, sslvrfClientOnce);
  187. TIdSSLVerifyModeSet = set of TIdSSLVerifyMode;
  188. TIdSSLCtxMode = (sslCtxClient, sslCtxServer);
  189. TIdSSLAction = (sslRead, sslWrite);
  190. const
  191. DEF_SSLVERSION = sslvTLSv1_3;
  192. DEF_SSLVERSIONS = [sslvTLSv1_3];
  193. P12_FILETYPE = 3;
  194. MAX_SSL_PASSWORD_LENGTH = 128;
  195. type
  196. TIdSSLULong = packed record
  197. case Byte of
  198. 0: (B1, B2, B3, B4: UInt8);
  199. 1: (W1, W2: UInt16);
  200. 2: (L1: Int32);
  201. 3: (C1: UInt32);
  202. end;
  203. TIdSSLEVP_MD = record
  204. Length: TIdC_UINT;
  205. MD: Array [0 .. EVP_MAX_MD_SIZE - 1] of TIdAnsiChar;
  206. end;
  207. TIdSSLByteArray = record
  208. Length: TIdC_UINT;
  209. Data: PByte;
  210. end;
  211. TIdX509 = class;
  212. TIdSSLIOHandlerSocketOpenSSL = class;
  213. TIdSSLCipher = class;
  214. TCallbackEvent = procedure(const AMsg: String) of object;
  215. TCallbackExEvent = procedure(ASender : TObject; const AsslSocket: PSSL;
  216. const AWhere, Aret: TIdC_INT; const AType, AMsg : String ) of object;
  217. TPasswordEvent = procedure(var Password: String) of object;
  218. TPasswordEventEx = procedure( ASender : TObject; var VPassword: String; const AIsWrite : Boolean) of object;
  219. TVerifyPeerEvent = function(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean of object;
  220. TIOHandlerNotify = procedure(ASender: TIdSSLIOHandlerSocketOpenSSL) of object;
  221. TIdSSLOptions = class(TPersistent)
  222. protected
  223. fsRootCertFile,
  224. fsCertFile,
  225. fsKeyFile,
  226. fsDHParamsFile: String;
  227. fMethod: TIdSSLVersion;
  228. fSSLVersions : TIdSSLVersions;
  229. fMode: TIdSSLMode;
  230. fVerifyDepth: Integer;
  231. fVerifyMode: TIdSSLVerifyModeSet;
  232. //fVerifyFile,
  233. fVerifyDirs: String;
  234. fCipherList: String;
  235. procedure AssignTo(Destination: TPersistent); override;
  236. procedure SetSSLVersions(const AValue : TIdSSLVersions);
  237. procedure SetMethod(const AValue : TIdSSLVersion);
  238. public
  239. constructor Create;
  240. // procedure Assign(ASource: TPersistent); override;
  241. published
  242. property RootCertFile: String read fsRootCertFile write fsRootCertFile;
  243. property CertFile: String read fsCertFile write fsCertFile;
  244. property KeyFile: String read fsKeyFile write fsKeyFile;
  245. property DHParamsFile: String read fsDHParamsFile write fsDHParamsFile;
  246. property Method: TIdSSLVersion read fMethod write SetMethod default DEF_SSLVERSION;
  247. property SSLVersions : TIdSSLVersions read fSSLVersions write SetSSLVersions default DEF_SSLVERSIONS;
  248. property Mode: TIdSSLMode read fMode write fMode;
  249. property VerifyMode: TIdSSLVerifyModeSet read fVerifyMode write fVerifyMode;
  250. property VerifyDepth: Integer read fVerifyDepth write fVerifyDepth;
  251. // property VerifyFile: String read fVerifyFile write fVerifyFile;
  252. property VerifyDirs: String read fVerifyDirs write fVerifyDirs;
  253. property CipherList: String read fCipherList write fCipherList;
  254. end;
  255. TIdSSLContext = class(TObject)
  256. protected
  257. fMethod: TIdSSLVersion;
  258. fSSLVersions : TIdSSLVersions;
  259. fMode: TIdSSLMode;
  260. fsRootCertFile, fsCertFile, fsKeyFile, fsDHParamsFile: String;
  261. fVerifyDepth: Integer;
  262. fVerifyMode: TIdSSLVerifyModeSet;
  263. // fVerifyFile: String;
  264. fVerifyDirs: String;
  265. fCipherList: String;
  266. fContext: PSSL_CTX;
  267. fStatusInfoOn: Boolean;
  268. // fPasswordRoutineOn: Boolean;
  269. fVerifyOn: Boolean;
  270. fSessionId: Integer;
  271. fCtxMode: TIdSSLCtxMode;
  272. procedure DestroyContext;
  273. function SetSSLMethod: PSSL_METHOD;
  274. procedure SetVerifyMode(Mode: TIdSSLVerifyModeSet; CheckRoutine: Boolean);
  275. function GetVerifyMode: TIdSSLVerifyModeSet;
  276. procedure InitContext(CtxMode: TIdSSLCtxMode);
  277. public
  278. {$IFDEF USE_OBJECT_ARC}[Weak]{$ENDIF} Parent: TObject;
  279. constructor Create;
  280. destructor Destroy; override;
  281. function Clone : TIdSSLContext;
  282. function LoadRootCert: Boolean;
  283. function LoadCert: Boolean;
  284. function LoadKey: Boolean;
  285. function LoadDHParams: Boolean;
  286. property StatusInfoOn: Boolean read fStatusInfoOn write fStatusInfoOn;
  287. // property PasswordRoutineOn: Boolean read fPasswordRoutineOn write fPasswordRoutineOn;
  288. property VerifyOn: Boolean read fVerifyOn write fVerifyOn;
  289. //THese can't be published in a TObject without a compiler warning.
  290. // published
  291. property SSLVersions : TIdSSLVersions read fSSLVersions write fSSLVersions;
  292. property Method: TIdSSLVersion read fMethod write fMethod;
  293. property Mode: TIdSSLMode read fMode write fMode;
  294. property RootCertFile: String read fsRootCertFile write fsRootCertFile;
  295. property CertFile: String read fsCertFile write fsCertFile;
  296. property CipherList: String read fCipherList write fCipherList;
  297. property KeyFile: String read fsKeyFile write fsKeyFile;
  298. property DHParamsFile: String read fsDHParamsFile write fsDHParamsFile;
  299. // property VerifyMode: TIdSSLVerifyModeSet read GetVerifyMode write SetVerifyMode;
  300. // property VerifyFile: String read fVerifyFile write fVerifyFile;
  301. property VerifyDirs: String read fVerifyDirs write fVerifyDirs;
  302. property VerifyMode: TIdSSLVerifyModeSet read fVerifyMode write fVerifyMode;
  303. property VerifyDepth: Integer read fVerifyDepth write fVerifyDepth;
  304. end;
  305. TIdSSLSocket = class(TObject)
  306. protected
  307. {$IFDEF USE_OBJECT_ARC}[Weak]{$ENDIF} fParent: TObject;
  308. fPeerCert: TIdX509;
  309. fSSL: PSSL;
  310. fSSLCipher: TIdSSLCipher;
  311. fSSLContext: TIdSSLContext;
  312. fHostName: String;
  313. function GetPeerCert: TIdX509;
  314. function GetSSLError(retCode: Integer): Integer;
  315. function GetSSLCipher: TIdSSLCipher;
  316. public
  317. constructor Create(Parent: TObject);
  318. destructor Destroy; override;
  319. procedure Accept(const pHandle: TIdStackSocketHandle);
  320. procedure Connect(const pHandle: TIdStackSocketHandle);
  321. function Send(const ABuffer : TIdBytes; AOffset, ALength: Integer): Integer;
  322. function Recv(var ABuffer : TIdBytes): Integer;
  323. function GetSessionID: TIdSSLByteArray;
  324. function GetSessionIDAsString:String;
  325. procedure SetCipherList(CipherList: String);
  326. //
  327. property PeerCert: TIdX509 read GetPeerCert;
  328. property Cipher: TIdSSLCipher read GetSSLCipher;
  329. property HostName: String read fHostName;
  330. end;
  331. // TIdSSLIOHandlerSocketOpenSSL and TIdServerIOHandlerSSLOpenSSL have some common
  332. // functions, but they do not have a common ancestor, so this interface helps
  333. // bridge the gap...
  334. IIdSSLOpenSSLCallbackHelper = interface(IInterface)
  335. ['{583F1209-10BA-4E06-8810-155FAEC415FE}']
  336. function GetPassword(const AIsWrite : Boolean): string;
  337. procedure StatusInfo(const ASSL: PSSL; AWhere, ARet: TIdC_INT; const AStatusStr: string);
  338. function VerifyPeer(ACertificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean;
  339. function GetIOHandlerSelf: TIdSSLIOHandlerSocketOpenSSL;
  340. end;
  341. TIdSSLIOHandlerSocketOpenSSL = class(TIdSSLIOHandlerSocketBase, IIdSSLOpenSSLCallbackHelper)
  342. protected
  343. fSSLContext: TIdSSLContext;
  344. fxSSLOptions: TIdSSLOptions;
  345. fSSLSocket: TIdSSLSocket;
  346. //fPeerCert: TIdX509;
  347. fOnStatusInfo: TCallbackEvent;
  348. FOnStatusInfoEx : TCallbackExEvent;
  349. fOnGetPassword: TPasswordEvent;
  350. fOnGetPasswordEx : TPasswordEventEx;
  351. fOnVerifyPeer: TVerifyPeerEvent;
  352. fSSLLayerClosed: Boolean;
  353. fOnBeforeConnect: TIOHandlerNotify;
  354. // function GetPeerCert: TIdX509;
  355. //procedure CreateSSLContext(axMode: TIdSSLMode);
  356. //
  357. procedure SetPassThrough(const Value: Boolean); override;
  358. procedure DoBeforeConnect(ASender: TIdSSLIOHandlerSocketOpenSSL); virtual;
  359. procedure DoStatusInfo(const AMsg: String); virtual;
  360. procedure DoStatusInfoEx(const AsslSocket: PSSL;
  361. const AWhere, Aret: TIdC_INT; const AWhereStr, ARetStr : String );
  362. procedure DoGetPassword(var Password: String); virtual;
  363. procedure DoGetPasswordEx(var VPassword: String; const AIsWrite : Boolean); virtual;
  364. function DoVerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean; virtual;
  365. function RecvEnc(var VBuffer: TIdBytes): Integer; override;
  366. function SendEnc(const ABuffer: TIdBytes; const AOffset, ALength: Integer): Integer; override;
  367. procedure Init;
  368. procedure OpenEncodedConnection; virtual;
  369. //some overrides from base classes
  370. procedure InitComponent; override;
  371. procedure ConnectClient; override;
  372. function CheckForError(ALastResult: Integer): Integer; override;
  373. procedure RaiseError(AError: Integer); override;
  374. { IIdSSLOpenSSLCallbackHelper }
  375. function GetPassword(const AIsWrite : Boolean): string;
  376. procedure StatusInfo(const ASslSocket: PSSL; AWhere, ARet: TIdC_INT; const AStatusStr: string);
  377. function VerifyPeer(ACertificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean;
  378. function GetIOHandlerSelf: TIdSSLIOHandlerSocketOpenSSL;
  379. public
  380. destructor Destroy; override;
  381. // TODO: add an AOwner parameter
  382. function Clone : TIdSSLIOHandlerSocketBase; override;
  383. procedure StartSSL; override;
  384. procedure AfterAccept; override;
  385. procedure Close; override;
  386. procedure Open; override;
  387. function Readable(AMSec: Integer = IdTimeoutDefault): Boolean; override;
  388. property SSLSocket: TIdSSLSocket read fSSLSocket write fSSLSocket;
  389. property OnBeforeConnect: TIOHandlerNotify read fOnBeforeConnect write fOnBeforeConnect;
  390. property SSLContext: TIdSSLContext read fSSLContext write fSSLContext;
  391. published
  392. property SSLOptions: TIdSSLOptions read fxSSLOptions write fxSSLOptions;
  393. property OnStatusInfo: TCallbackEvent read fOnStatusInfo write fOnStatusInfo;
  394. property OnStatusInfoEx: TCallbackExEvent read fOnStatusInfoEx write fOnStatusInfoEx;
  395. property OnGetPassword: TPasswordEvent read fOnGetPassword write fOnGetPassword;
  396. property OnGetPasswordEx : TPasswordEventEx read fOnGetPasswordEx write fOnGetPasswordEx;
  397. property OnVerifyPeer: TVerifyPeerEvent read fOnVerifyPeer write fOnVerifyPeer;
  398. end;
  399. TIdServerIOHandlerSSLOpenSSL = class(TIdServerIOHandlerSSLBase, IIdSSLOpenSSLCallbackHelper)
  400. protected
  401. fxSSLOptions: TIdSSLOptions;
  402. fSSLContext: TIdSSLContext;
  403. fOnStatusInfo: TCallbackEvent;
  404. FOnStatusInfoEx : TCallbackExEvent;
  405. fOnGetPassword: TPasswordEvent;
  406. fOnGetPasswordEx : TPasswordEventEx;
  407. fOnVerifyPeer: TVerifyPeerEvent;
  408. //
  409. //procedure CreateSSLContext(axMode: TIdSSLMode);
  410. //procedure CreateSSLContext;
  411. //
  412. procedure DoStatusInfo(const AMsg: String); virtual;
  413. procedure DoStatusInfoEx(const AsslSocket: PSSL;
  414. const AWhere, Aret: TIdC_INT; const AWhereStr, ARetStr : String );
  415. procedure DoGetPassword(var Password: String); virtual;
  416. //TPasswordEventEx
  417. procedure DoGetPasswordEx(var VPassword: String; const AIsWrite : Boolean); virtual;
  418. function DoVerifyPeer(Certificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean; virtual;
  419. procedure InitComponent; override;
  420. { IIdSSLOpenSSLCallbackHelper }
  421. function GetPassword(const AIsWrite : Boolean): string;
  422. procedure StatusInfo(const ASslSocket: PSSL; AWhere, ARet: TIdC_INT; const AStatusStr: string);
  423. function VerifyPeer(ACertificate: TIdX509; AOk: Boolean; ADepth, AError: Integer): Boolean;
  424. function GetIOHandlerSelf: TIdSSLIOHandlerSocketOpenSSL;
  425. public
  426. procedure Init; override;
  427. procedure Shutdown; override;
  428. // AListenerThread is a thread and not a yarn. Its the listener thread.
  429. function Accept(ASocket: TIdSocketHandle; AListenerThread: TIdThread;
  430. AYarn: TIdYarn): TIdIOHandler; override;
  431. // function Accept(ASocket: TIdSocketHandle; AThread: TIdThread) : TIdIOHandler; override;
  432. destructor Destroy; override;
  433. function MakeClientIOHandler : TIdSSLIOHandlerSocketBase; override;
  434. //
  435. function MakeFTPSvrPort : TIdSSLIOHandlerSocketBase; override;
  436. function MakeFTPSvrPasv : TIdSSLIOHandlerSocketBase; override;
  437. //
  438. property SSLContext: TIdSSLContext read fSSLContext;
  439. published
  440. property SSLOptions: TIdSSLOptions read fxSSLOptions write fxSSLOptions;
  441. property OnStatusInfo: TCallbackEvent read fOnStatusInfo write fOnStatusInfo;
  442. property OnStatusInfoEx: TCallbackExEvent read fOnStatusInfoEx write fOnStatusInfoEx;
  443. property OnGetPassword: TPasswordEvent read fOnGetPassword write fOnGetPassword;
  444. property OnGetPasswordEx : TPasswordEventEx read fOnGetPasswordEx write fOnGetPasswordEx;
  445. property OnVerifyPeer: TVerifyPeerEvent read fOnVerifyPeer write fOnVerifyPeer;
  446. end;
  447. TIdX509Name = class(TObject)
  448. protected
  449. fX509Name: PX509_NAME;
  450. function CertInOneLine: String;
  451. function GetHash: TIdSSLULong;
  452. function GetHashAsString: String;
  453. public
  454. constructor Create(aX509Name: PX509_NAME);
  455. //
  456. property Hash: TIdSSLULong read GetHash;
  457. property HashAsString: string read GetHashAsString;
  458. property OneLine: string read CertInOneLine;
  459. //
  460. property CertificateName: PX509_NAME read fX509Name;
  461. end;
  462. TIdX509Info = class(TObject)
  463. protected
  464. //Do not free this here because it belongs
  465. //to the X509 or something else.
  466. FX509 : PX509;
  467. public
  468. constructor Create( aX509: PX509);
  469. //
  470. property Certificate: PX509 read FX509;
  471. end;
  472. TIdX509Fingerprints = class(TIdX509Info)
  473. protected
  474. function GetMD5: TIdSSLEVP_MD;
  475. function GetMD5AsString:String;
  476. function GetSHA1: TIdSSLEVP_MD;
  477. function GetSHA1AsString:String;
  478. function GetSHA224 : TIdSSLEVP_MD;
  479. function GetSHA224AsString : String;
  480. function GetSHA256 : TIdSSLEVP_MD;
  481. function GetSHA256AsString : String;
  482. function GetSHA384 : TIdSSLEVP_MD;
  483. function GetSHA384AsString : String;
  484. function GetSHA512 : TIdSSLEVP_MD;
  485. function GetSHA512AsString : String;
  486. public
  487. property MD5 : TIdSSLEVP_MD read GetMD5;
  488. property MD5AsString : String read GetMD5AsString;
  489. {IMPORTANT!!!
  490. FIPS approves only these algorithms for hashing.
  491. SHA-1
  492. SHA-224
  493. SHA-256
  494. SHA-384
  495. SHA-512
  496. http://csrc.nist.gov/CryptoToolkit/tkhash.html
  497. }
  498. property SHA1 : TIdSSLEVP_MD read GetSHA1;
  499. property SHA1AsString : String read GetSHA1AsString;
  500. property SHA224 : TIdSSLEVP_MD read GetSHA224;
  501. property SHA224AsString : String read GetSHA224AsString;
  502. property SHA256 : TIdSSLEVP_MD read GetSHA256;
  503. property SHA256AsString : String read GetSHA256AsString;
  504. property SHA384 : TIdSSLEVP_MD read GetSHA384;
  505. property SHA384AsString : String read GetSHA384AsString;
  506. property SHA512 : TIdSSLEVP_MD read GetSHA512;
  507. property SHA512AsString : String read GetSHA512AsString;
  508. end;
  509. TIdX509SigInfo = class(TIdX509Info)
  510. protected
  511. function GetSignature : String;
  512. function GetSigType : TIdC_INT;
  513. function GetSigTypeAsString : String;
  514. public
  515. property Signature : String read GetSignature;
  516. property SigType : TIdC_INT read GetSigType ;
  517. property SigTypeAsString : String read GetSigTypeAsString;
  518. end;
  519. TIdX509 = class(TObject)
  520. protected
  521. FFingerprints : TIdX509Fingerprints;
  522. FSigInfo : TIdX509SigInfo;
  523. FCanFreeX509 : Boolean;
  524. FX509 : PX509;
  525. FSubject : TIdX509Name;
  526. FIssuer : TIdX509Name;
  527. FDisplayInfo : TStrings;
  528. function RSubject:TIdX509Name;
  529. function RIssuer:TIdX509Name;
  530. function RnotBefore:TDateTime;
  531. function RnotAfter:TDateTime;
  532. function RFingerprint:TIdSSLEVP_MD;
  533. function RFingerprintAsString:String;
  534. function GetSerialNumber: String;
  535. function GetVersion : TIdC_LONG;
  536. function GetDisplayInfo : TStrings;
  537. public
  538. Constructor Create(aX509: PX509; aCanFreeX509: Boolean = True); virtual;
  539. Destructor Destroy; override;
  540. property Version : TIdC_LONG read GetVersion;
  541. //
  542. property SigInfo : TIdX509SigInfo read FSigInfo;
  543. property Fingerprints : TIdX509Fingerprints read FFingerprints;
  544. //
  545. property Fingerprint: TIdSSLEVP_MD read RFingerprint;
  546. property FingerprintAsString: String read RFingerprintAsString;
  547. property Subject: TIdX509Name read RSubject;
  548. property Issuer: TIdX509Name read RIssuer;
  549. property notBefore: TDateTime read RnotBefore;
  550. property notAfter: TDateTime read RnotAfter;
  551. property SerialNumber : string read GetSerialNumber;
  552. property DisplayInfo : TStrings read GetDisplayInfo;
  553. //
  554. property Certificate: PX509 read FX509;
  555. end;
  556. TIdSSLCipher = class(TObject)
  557. protected
  558. FSSLSocket: TIdSSLSocket;
  559. function GetDescription: String;
  560. function GetName: String;
  561. function GetBits: Integer;
  562. function GetVersion: String;
  563. public
  564. constructor Create(AOwner: TIdSSLSocket);
  565. destructor Destroy; override;
  566. //These can't be published without a compiler warning.
  567. // published
  568. property Description: String read GetDescription;
  569. property Name: String read GetName;
  570. property Bits: Integer read GetBits;
  571. property Version: String read GetVersion;
  572. end;
  573. EIdOSSLCouldNotLoadSSLLibrary = class(EIdOpenSSLError);
  574. EIdOSSLModeNotSet = class(EIdOpenSSLError);
  575. EIdOSSLGetMethodError = class(EIdOpenSSLError);
  576. EIdOSSLCreatingSessionError = class(EIdOpenSSLError);
  577. EIdOSSLCreatingContextError = class(EIdOpenSSLAPICryptoError);
  578. EIdOSSLLoadingRootCertError = class(EIdOpenSSLAPICryptoError);
  579. EIdOSSLLoadingCertError = class(EIdOpenSSLAPICryptoError);
  580. EIdOSSLLoadingKeyError = class(EIdOpenSSLAPICryptoError);
  581. EIdOSSLLoadingDHParamsError = class(EIdOpenSSLAPICryptoError);
  582. EIdOSSLSettingCipherError = class(EIdOpenSSLError);
  583. EIdOSSLFDSetError = class(EIdOpenSSLAPISSLError);
  584. EIdOSSLDataBindingError = class(EIdOpenSSLAPISSLError);
  585. EIdOSSLAcceptError = class(EIdOpenSSLAPISSLError);
  586. EIdOSSLConnectError = class(EIdOpenSSLAPISSLError);
  587. {$IFNDEF OPENSSL_NO_TLSEXT}
  588. EIdOSSLSettingTLSHostNameError = class(EIdOpenSSLAPISSLError);
  589. {$ENDIF}
  590. function LoadOpenSSLLibrary: Boolean;
  591. procedure UnLoadOpenSSLLibrary;
  592. function OpenSSLVersion: string;
  593. implementation
  594. uses
  595. {$IFDEF HAS_UNIT_Generics_Collections}
  596. System.Generics.Collections,
  597. {$ENDIF}
  598. {$IFDEF USE_VCL_POSIX}
  599. Posix.SysTime,
  600. Posix.Time,
  601. Posix.Unistd,
  602. {$ENDIF}
  603. IdFIPS,
  604. IdResourceStringsCore,
  605. IdResourceStringsProtocols,
  606. IdResourceStringsOpenSSL,
  607. IdStack,
  608. IdStackBSDBase,
  609. IdAntiFreezeBase,
  610. IdExceptionCore,
  611. IdResourceStrings,
  612. IdThreadSafe,
  613. IdCustomTransparentProxy,
  614. IdURI,
  615. SysUtils,
  616. SyncObjs;
  617. type
  618. // TODO: TIdThreadSafeObjectList instead?
  619. {$IFDEF HAS_GENERICS_TThreadList}
  620. TIdCriticalSectionThreadList = TThreadList<TIdCriticalSection>;
  621. TIdCriticalSectionList = TList<TIdCriticalSection>;
  622. {$ELSE}
  623. // TODO: flesh out to match TThreadList<TIdCriticalSection> and TList<TIdCriticalSection> on non-Generics compilers
  624. TIdCriticalSectionThreadList = TThreadList;
  625. TIdCriticalSectionList = TList;
  626. {$ENDIF}
  627. // RLebeau 1/24/2019: defining this as a private implementation for now to
  628. // avoid a change in the public interface above. This should be rolled into
  629. // the public interface at some point...
  630. TIdSSLOptions_Internal = class(TIdSSLOptions)
  631. public
  632. {$IFDEF USE_OBJECT_ARC}[Weak]{$ENDIF} Parent: TObject;
  633. end;
  634. var
  635. SSLIsLoaded: TIdThreadSafeBoolean = nil;
  636. LockInfoCB: TIdCriticalSection = nil;
  637. LockPassCB: TIdCriticalSection = nil;
  638. LockVerifyCB: TIdCriticalSection = nil;
  639. CallbackLockList: TIdCriticalSectionThreadList = nil;
  640. procedure GetStateVars(const sslSocket: PSSL; AWhere, Aret: TIdC_INT; var VTypeStr, VMsg : String);
  641. {$IFDEF USE_INLINE}inline;{$ENDIF}
  642. begin
  643. case AWhere of
  644. SSL_CB_ALERT :
  645. begin
  646. VTypeStr := IndyFormat( RSOSSLAlert,[SSL_alert_type_string_long(Aret)]);
  647. VMsg := String(SSL_alert_type_string_long(Aret));
  648. end;
  649. SSL_CB_READ_ALERT :
  650. begin
  651. VTypeStr := IndyFormat(RSOSSLReadAlert,[SSL_alert_type_string_long(Aret)]);
  652. VMsg := String( SSL_alert_desc_string_long(Aret));
  653. end;
  654. SSL_CB_WRITE_ALERT :
  655. begin
  656. VTypeStr := IndyFormat(RSOSSLWriteAlert,[SSL_alert_type_string_long(Aret)]);
  657. VMsg := String( SSL_alert_desc_string_long(Aret));
  658. end;
  659. SSL_CB_ACCEPT_LOOP :
  660. begin
  661. VTypeStr := RSOSSLAcceptLoop;
  662. VMsg := String( SSL_state_string_long(sslSocket));
  663. end;
  664. SSL_CB_ACCEPT_EXIT :
  665. begin
  666. if ARet < 0 then begin
  667. VTypeStr := RSOSSLAcceptError;
  668. end else begin
  669. if ARet = 0 then begin
  670. VTypeStr := RSOSSLAcceptFailed;
  671. end else begin
  672. VTypeStr := RSOSSLAcceptExit;
  673. end;
  674. end;
  675. VMsg := String( SSL_state_string_long(sslSocket) );
  676. end;
  677. SSL_CB_CONNECT_LOOP :
  678. begin
  679. VTypeStr := RSOSSLConnectLoop;
  680. VMsg := String( SSL_state_string_long(sslSocket) );
  681. end;
  682. SSL_CB_CONNECT_EXIT :
  683. begin
  684. if ARet < 0 then begin
  685. VTypeStr := RSOSSLConnectError;
  686. end else begin
  687. if ARet = 0 then begin
  688. VTypeStr := RSOSSLConnectFailed
  689. end else begin
  690. VTypeStr := RSOSSLConnectExit;
  691. end;
  692. end;
  693. VMsg := String( SSL_state_string_long(sslSocket) );
  694. end;
  695. SSL_CB_HANDSHAKE_START :
  696. begin
  697. VTypeStr := RSOSSLHandshakeStart;
  698. VMsg := String( SSL_state_string_long(sslSocket) );
  699. end;
  700. SSL_CB_HANDSHAKE_DONE :
  701. begin
  702. VTypeStr := RSOSSLHandshakeDone;
  703. VMsg := String( SSL_state_string_long(sslSocket) );
  704. end;
  705. end;
  706. {var LW : TIdC_INT;
  707. begin
  708. VMsg := '';
  709. LW := Awhere and (not SSL_ST_MASK);
  710. if (LW and SSL_ST_CONNECT) > 0 then begin
  711. VWhereStr := 'SSL_connect:';
  712. end else begin
  713. if (LW and SSL_ST_ACCEPT) > 0 then begin
  714. VWhereStr := ' SSL_accept:';
  715. end else begin
  716. VWhereStr := ' undefined:';
  717. end;
  718. end;
  719. // IdSslStateStringLong
  720. if (Awhere and SSL_CB_LOOP) > 0 then begin
  721. VMsg := IdSslStateStringLong(sslSocket);
  722. end else begin
  723. if (Awhere and SSL_CB_ALERT) > 0 then begin
  724. if (Awhere and SSL_CB_READ > 0) then begin
  725. VWhereStr := VWhereStr + ' read:'+ IdSslAlertTypeStringLong(Aret);
  726. end else begin
  727. VWhereStr := VWhereStr + 'write:'+ IdSslAlertTypeStringLong(Aret);
  728. end;;
  729. VMsg := IdSslAlertDescStringLong(Aret);
  730. end else begin
  731. if (Awhere and SSL_CB_EXIT) > 0 then begin
  732. if ARet = 0 then begin
  733. VWhereStr := VWhereStr +'failed';
  734. VMsg := IdSslStateStringLong(sslSocket);
  735. end else begin
  736. if ARet < 0 then begin
  737. VWhereStr := VWhereStr +'error';
  738. VMsg := IdSslStateStringLong(sslSocket);
  739. end;
  740. end;
  741. end;
  742. end;
  743. end; }
  744. end;
  745. function PasswordCallback(buf: PIdAnsiChar; size: TIdC_INT; rwflag: TIdC_INT; userdata: Pointer): TIdC_INT; cdecl;
  746. {$IFDEF USE_MARSHALLED_PTRS}
  747. type
  748. TBytesPtr = ^TBytes;
  749. {$ENDIF}
  750. var
  751. Password: String;
  752. {$IFDEF STRING_IS_UNICODE}
  753. LPassword: TIdBytes;
  754. {$ENDIF}
  755. IdSSLContext: TIdSSLContext;
  756. LErr : Integer;
  757. LHelper: IIdSSLOpenSSLCallbackHelper;
  758. begin
  759. //Preserve last eror just in case OpenSSL is using it and we do something that
  760. //clobers it. CYA.
  761. LErr := GStack.WSGetLastError;
  762. try
  763. LockPassCB.Enter;
  764. try
  765. Password := ''; {Do not Localize}
  766. IdSSLContext := TIdSSLContext(userdata);
  767. if Supports(IdSSLContext.Parent, IIdSSLOpenSSLCallbackHelper, IInterface(LHelper)) then begin
  768. Password := LHelper.GetPassword(rwflag > 0);
  769. LHelper := nil;
  770. end;
  771. FillChar(buf^, size, 0);
  772. {$IFDEF STRING_IS_UNICODE}
  773. LPassword := IndyTextEncoding_OSDefault.GetBytes(Password);
  774. if Length(LPassword) > 0 then begin
  775. {$IFDEF USE_MARSHALLED_PTRS}
  776. TMarshal.Copy(TBytesPtr(@LPassword)^, 0, TPtrWrapper.Create(buf), IndyMin(Length(LPassword), size));
  777. {$ELSE}
  778. Move(LPassword[0], buf^, IndyMin(Length(LPassword), size));
  779. {$ENDIF}
  780. end;
  781. Result := Length(LPassword);
  782. {$ELSE}
  783. StrPLCopy(buf, Password, size);
  784. Result := Length(Password);
  785. {$ENDIF}
  786. buf[size-1] := #0; // RLebeau: truncate the password if needed
  787. finally
  788. LockPassCB.Leave;
  789. end;
  790. finally
  791. GStack.WSSetLastError(LErr);
  792. end;
  793. end;
  794. procedure InfoCallback(const sslSocket: PSSL; where, ret: TIdC_INT); cdecl;
  795. var
  796. IdSSLSocket: TIdSSLSocket;
  797. StatusStr : String;
  798. LErr : Integer;
  799. LHelper: IIdSSLOpenSSLCallbackHelper;
  800. begin
  801. {
  802. You have to save the value of WSGetLastError as some Operating System API
  803. function calls will reset that value and we can't know what a programmer will
  804. do in this event. We need the value of WSGetLastError so we can report
  805. an underlying socket error when the OpenSSL function returns.
  806. JPM.
  807. }
  808. LErr := GStack.WSGetLastError;
  809. try
  810. LockInfoCB.Enter;
  811. try
  812. IdSSLSocket := TIdSSLSocket(SSL_get_app_data(sslSocket));
  813. if Assigned(IdSSLSocket) then begin
  814. if Supports(IdSSLSocket.fParent, IIdSSLOpenSSLCallbackHelper, IInterface(LHelper)) then begin
  815. StatusStr := IndyFormat(RSOSSLStatusString, [String(SSL_state_string_long(sslSocket))]);
  816. LHelper.StatusInfo(sslSocket, where, ret, StatusStr);
  817. LHelper := nil;
  818. end;
  819. end;
  820. finally
  821. LockInfoCB.Leave;
  822. end;
  823. finally
  824. GStack.WSSetLastError(LErr);
  825. end;
  826. end;
  827. function TranslateInternalVerifyToSSL(Mode: TIdSSLVerifyModeSet): Integer;
  828. {$IFDEF USE_INLINE} inline; {$ENDIF}
  829. begin
  830. Result := SSL_VERIFY_NONE;
  831. if sslvrfPeer in Mode then begin
  832. Result := Result or SSL_VERIFY_PEER;
  833. end;
  834. if sslvrfFailIfNoPeerCert in Mode then begin
  835. Result := Result or SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
  836. end;
  837. if sslvrfClientOnce in Mode then begin
  838. Result := Result or SSL_VERIFY_CLIENT_ONCE;
  839. end;
  840. end;
  841. function VerifyCallback(Ok: TIdC_INT; ctx: PX509_STORE_CTX): TIdC_INT; cdecl;
  842. var
  843. hcert: PX509;
  844. Certificate: TIdX509;
  845. hSSL: PSSL;
  846. IdSSLSocket: TIdSSLSocket;
  847. // str: String;
  848. VerifiedOK: Boolean;
  849. Depth: Integer;
  850. Error: Integer;
  851. LOk: Boolean;
  852. LHelper: IIdSSLOpenSSLCallbackHelper;
  853. begin
  854. LockVerifyCB.Enter;
  855. try
  856. VerifiedOK := True;
  857. try
  858. hSSL := X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx);
  859. if hSSL = nil then begin
  860. Result := Ok;
  861. Exit;
  862. end;
  863. hcert := X509_STORE_CTX_get_current_cert(ctx);
  864. Certificate := TIdX509.Create(hcert, False); // the certificate is owned by the store
  865. try
  866. IdSSLSocket := TIdSSLSocket(SSL_get_app_data(hSSL));
  867. if Assigned(IdSSLSocket) then begin
  868. Error := X509_STORE_CTX_get_error(ctx);
  869. Depth := X509_STORE_CTX_get_error_depth(ctx);
  870. if not ((Ok > 0) and (IdSSLSocket.fSSLContext.VerifyDepth >= Depth)) then begin
  871. Ok := 0;
  872. {if Error = X509_V_OK then begin
  873. Error := X509_V_ERR_CERT_CHAIN_TOO_LONG;
  874. end;}
  875. end;
  876. LOk := False;
  877. if Ok = 1 then begin
  878. LOk := True;
  879. end;
  880. if Supports(IdSSLSocket.fParent, IIdSSLOpenSSLCallbackHelper, IInterface(LHelper)) then begin
  881. VerifiedOK := LHelper.VerifyPeer(Certificate, LOk, Depth, Error);
  882. LHelper := nil;
  883. end;
  884. end;
  885. finally
  886. FreeAndNil(Certificate);
  887. end;
  888. except
  889. VerifiedOK := False;
  890. end;
  891. //if VerifiedOK and (Ok > 0) then begin
  892. if VerifiedOK {and (Ok > 0)} then begin
  893. Result := 1;
  894. end
  895. else begin
  896. Result := 0;
  897. end;
  898. // Result := Ok; // testing
  899. finally
  900. LockVerifyCB.Leave;
  901. end;
  902. end;
  903. //////////////////////////////////////////////////////
  904. // Utilities
  905. //////////////////////////////////////////////////////
  906. function IndySSL_load_client_CA_file(const AFileName: String) : PSTACK_OF_X509_NAME; forward;
  907. function IndySSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const AFileName: String;
  908. AType: Integer): TIdC_INT; forward;
  909. function IndySSL_CTX_use_certificate_file(ctx: PSSL_CTX; const AFileName: String;
  910. AType: Integer): TIdC_INT; forward;
  911. function IndySSL_CTX_use_certificate_chain_file(ctx :PSSL_CTX;
  912. const AFileName: String) : TIdC_INT; forward;
  913. function IndyX509_STORE_load_locations(ctx: PX509_STORE;
  914. const AFileName, APathName: String): TIdC_INT; forward;
  915. function IndySSL_CTX_load_verify_locations(ctx: PSSL_CTX;
  916. const ACAFile, ACAPath: String): TIdC_INT; forward;
  917. function IndySSL_CTX_use_DHparams_file(ctx: PSSL_CTX;
  918. const AFileName: String; AType: Integer): TIdC_INT; forward;
  919. // TODO
  920. {
  921. function d2i_DHparams_bio(bp: PBIO; x: PPointer): PDH; inline;
  922. begin
  923. Result := PDH(ASN1_d2i_bio(@DH_new, @d2i_DHparams, bp, x));
  924. end;
  925. }
  926. // SSL_CTX_use_PrivateKey_file() and SSL_CTX_use_certificate_file() do not
  927. // natively support PKCS12 certificates/keys, only PEM/ASN1, so load them
  928. // manually...
  929. function IndySSL_CTX_use_PrivateKey_file_PKCS12(ctx: PSSL_CTX; const AFileName: String): TIdC_INT;
  930. var
  931. LM: TMemoryStream;
  932. B: PBIO;
  933. LKey: PEVP_PKEY;
  934. LCert: PX509;
  935. P12: PPKCS12;
  936. CertChain: PSTACK_OF_X509;
  937. LPassword: array of TIdAnsiChar;
  938. LPasswordPtr: PIdAnsiChar;
  939. begin
  940. Result := 0;
  941. LM := nil;
  942. try
  943. LM := TMemoryStream.Create;
  944. LM.LoadFromFile(AFileName);
  945. except
  946. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  947. // Follow the OpenSSL .DLL Error conventions.
  948. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_SYS_LIB);
  949. LM.Free;
  950. Exit;
  951. end;
  952. try
  953. B := BIO_new_mem_buf(LM.Memory, LM.Size);
  954. if not Assigned(B) then begin
  955. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB);
  956. Exit;
  957. end;
  958. try
  959. SetLength(LPassword, MAX_SSL_PASSWORD_LENGTH+1);
  960. LPassword[MAX_SSL_PASSWORD_LENGTH] := TIdAnsiChar(0);
  961. LPasswordPtr := PIdAnsiChar(LPassword);
  962. if Assigned(ctx^.default_passwd_callback) then begin
  963. ctx^.default_passwd_callback(LPasswordPtr, MAX_SSL_PASSWORD_LENGTH, 0, ctx^.default_passwd_callback_userdata);
  964. // TODO: check return value for failure
  965. end else begin
  966. // TODO: call PEM_def_callback(), like PEM_read_bio_X509() does
  967. // when default_passwd_callback is nil
  968. end;
  969. P12 := d2i_PKCS12_bio(B, nil);
  970. if not Assigned(P12) then begin
  971. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PKCS12_LIB);
  972. Exit;
  973. end;
  974. try
  975. CertChain := nil;
  976. if PKCS12_parse(P12, LPasswordPtr, LKey, LCert, @CertChain) <> 1 then begin
  977. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PKCS12_LIB);
  978. Exit;
  979. end;
  980. try
  981. Result := SSL_CTX_use_PrivateKey(ctx, LKey);
  982. finally
  983. sk_pop_free(CertChain, @X509_free);
  984. X509_free(LCert);
  985. EVP_PKEY_free(LKey);
  986. end;
  987. finally
  988. PKCS12_free(P12);
  989. end;
  990. finally
  991. BIO_free(B);
  992. end;
  993. finally
  994. FreeAndNil(LM);
  995. end;
  996. end;
  997. function IndySSL_CTX_use_certificate_file_PKCS12(ctx: PSSL_CTX; const AFileName: String): TIdC_INT;
  998. var
  999. LM: TMemoryStream;
  1000. B: PBIO;
  1001. LCert: PX509;
  1002. P12: PPKCS12;
  1003. PKey: PEVP_PKEY;
  1004. CertChain: PSTACK_OF_X509;
  1005. LPassword: array of TIdAnsiChar;
  1006. LPasswordPtr: PIdAnsiChar;
  1007. begin
  1008. Result := 0;
  1009. LM := nil;
  1010. try
  1011. LM := TMemoryStream.Create;
  1012. LM.LoadFromFile(AFileName);
  1013. except
  1014. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  1015. // Follow the OpenSSL .DLL Error conventions.
  1016. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB);
  1017. LM.Free;
  1018. Exit;
  1019. end;
  1020. try
  1021. B := BIO_new_mem_buf(LM.Memory, LM.Size);
  1022. if not Assigned(B) then begin
  1023. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB);
  1024. Exit;
  1025. end;
  1026. try
  1027. SetLength(LPassword, MAX_SSL_PASSWORD_LENGTH+1);
  1028. LPassword[MAX_SSL_PASSWORD_LENGTH] := TIdAnsiChar(0);
  1029. LPasswordPtr := PIdAnsiChar(LPassword);
  1030. if Assigned(ctx^.default_passwd_callback) then begin
  1031. ctx^.default_passwd_callback(LPasswordPtr, MAX_SSL_PASSWORD_LENGTH, 0, ctx^.default_passwd_callback_userdata);
  1032. // TODO: check return value for failure
  1033. end else begin
  1034. // TODO: call PEM_def_callback(), like PEM_read_bio_X509() does
  1035. // when default_passwd_callback is nil
  1036. end;
  1037. P12 := d2i_PKCS12_bio(B, nil);
  1038. if not Assigned(P12) then
  1039. begin
  1040. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PKCS12_LIB);
  1041. Exit;
  1042. end;
  1043. try
  1044. CertChain := nil;
  1045. if PKCS12_parse(P12, LPasswordPtr, PKey, LCert, @CertChain) <> 1 then begin
  1046. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PKCS12_LIB);
  1047. Exit;
  1048. end;
  1049. try
  1050. Result := SSL_CTX_use_certificate(ctx, LCert);
  1051. finally
  1052. sk_pop_free(CertChain, @X509_free);
  1053. X509_free(LCert);
  1054. EVP_PKEY_free(PKey);
  1055. end;
  1056. finally
  1057. PKCS12_free(P12);
  1058. end;
  1059. finally
  1060. BIO_free(B);
  1061. end;
  1062. finally
  1063. FreeAndNil(LM);
  1064. end;
  1065. end;
  1066. {
  1067. IMPORTANT!!!
  1068. OpenSSL can not handle Unicode file names at all. On Posix systems, UTF8 File
  1069. names can be used with OpenSSL. The Windows operating system does not accept
  1070. UTF8 file names at all so we have our own routines that will handle Unicode
  1071. filenames. Most of this section of code is based on code in the OpenSSL .DLL
  1072. which is copyrighted by the OpenSSL developers. Some of it is translated into
  1073. Pascal and made some modifications so that it will handle Unicode filenames.
  1074. }
  1075. {$IFDEF STRING_IS_UNICODE}
  1076. {$IFDEF WINDOWS}
  1077. function Indy_unicode_X509_load_cert_crl_file(ctx: PX509_LOOKUP; const AFileName: String;
  1078. const _type: TIdC_INT): TIdC_INT; forward;
  1079. function Indy_unicode_X509_load_cert_file(ctx: PX509_LOOKUP; const AFileName: String;
  1080. _type: TIdC_INT): TIdC_INT; forward;
  1081. {
  1082. This is for some file lookup definitions for a LOOKUP method that
  1083. uses Unicode filenames instead of ASCII or UTF8. It is not meant
  1084. to be portable at all.
  1085. }
  1086. function by_Indy_unicode_file_ctrl(ctx: PX509_LOOKUP; cmd: TIdC_INT;
  1087. const argc: PAnsiChar; argl: TIdC_LONG; out ret: PAnsiChar): TIdC_INT;
  1088. cdecl; forward;
  1089. const
  1090. Indy_x509_unicode_file_lookup: X509_LOOKUP_METHOD =
  1091. (
  1092. name: PAnsiChar('Load file into cache');
  1093. new_item: nil; // * new */
  1094. free: nil; // * free */
  1095. init: nil; // * init */
  1096. shutdown: nil; // * shutdown */
  1097. ctrl: by_Indy_unicode_file_ctrl; // * ctrl */
  1098. get_by_subject: nil; // * get_by_subject */
  1099. get_by_issuer_serial: nil; // * get_by_issuer_serial */
  1100. get_by_fingerprint: nil; // * get_by_fingerprint */
  1101. get_by_alias: nil // * get_by_alias */
  1102. );
  1103. function Indy_Unicode_X509_LOOKUP_file(): PX509_LOOKUP_METHOD cdecl;
  1104. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1105. begin
  1106. Result := @Indy_x509_unicode_file_lookup;
  1107. end;
  1108. function by_Indy_unicode_file_ctrl(ctx: PX509_LOOKUP; cmd: TIdC_INT;
  1109. const argc: PAnsiChar; argl: TIdC_LONG; out ret: PAnsiChar): TIdC_INT; cdecl;
  1110. var
  1111. LOk: TIdC_INT;
  1112. LFileName: String;
  1113. begin
  1114. LOk := 0;
  1115. case cmd of
  1116. X509_L_FILE_LOAD:
  1117. begin
  1118. // Note that typecasting an AnsiChar as a WideChar below is normally a crazy
  1119. // thing to do. The thing is that the OpenSSL API is based on PAnsiChar, and
  1120. // we are writing this function just for Unicode filenames. argc is actually
  1121. // a PWideChar that has been coerced into a PAnsiChar so it can pass through
  1122. // OpenSSL APIs...
  1123. case argl of
  1124. X509_FILETYPE_DEFAULT:
  1125. begin
  1126. LFileName := GetEnvironmentVariable(String(X509_get_default_cert_file_env));
  1127. if LFileName = '' then begin
  1128. LFileName := String(X509_get_default_cert_file);
  1129. end;
  1130. LOk := Ord(Indy_unicode_X509_load_cert_crl_file(ctx, LFileName, X509_FILETYPE_PEM) <> 0);
  1131. if LOk = 0 then begin
  1132. X509err(X509_F_BY_FILE_CTRL, X509_R_LOADING_DEFAULTS);
  1133. end;
  1134. end;
  1135. X509_FILETYPE_PEM:
  1136. begin
  1137. LFileName := PWideChar(Pointer(argc));
  1138. LOk := Ord(Indy_unicode_X509_load_cert_crl_file(ctx, LFileName, X509_FILETYPE_PEM) <> 0);
  1139. end;
  1140. else
  1141. LFileName := PWideChar(Pointer(argc));
  1142. LOk := Ord(Indy_unicode_X509_load_cert_file(ctx, LFileName, TIdC_INT(argl)) <> 0);
  1143. end;
  1144. end;
  1145. end;
  1146. Result := LOk;
  1147. end;
  1148. function Indy_unicode_X509_load_cert_file(ctx: PX509_LOOKUP; const AFileName: String;
  1149. _type: TIdC_INT): TIdC_INT;
  1150. var
  1151. LM: TMemoryStream;
  1152. Lin: PBIO;
  1153. LX: PX509;
  1154. i, count: Integer;
  1155. begin
  1156. Result := 0;
  1157. count := 0;
  1158. if AFileName = '' then begin
  1159. Result := 1;
  1160. Exit;
  1161. end;
  1162. LM := nil;
  1163. try
  1164. LM := TMemoryStream.Create;
  1165. LM.LoadFromFile(AFileName);
  1166. except
  1167. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  1168. // Follow the OpenSSL .DLL Error conventions.
  1169. X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_SYS_LIB);
  1170. LM.Free;
  1171. Exit;
  1172. end;
  1173. try
  1174. Lin := BIO_new_mem_buf(LM.Memory, LM.Size);
  1175. if not Assigned(Lin) then begin
  1176. X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_SYS_LIB);
  1177. Exit;
  1178. end;
  1179. try
  1180. case _type of
  1181. X509_FILETYPE_PEM:
  1182. begin
  1183. repeat
  1184. LX := PEM_read_bio_X509_AUX(Lin, nil, nil, nil);
  1185. if not Assigned(LX) then begin
  1186. if ((ERR_GET_REASON(ERR_peek_last_error())
  1187. = PEM_R_NO_START_LINE) and (count > 0)) then begin
  1188. ERR_clear_error();
  1189. Break;
  1190. end else begin
  1191. X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_PEM_LIB);
  1192. Exit;
  1193. end;
  1194. end;
  1195. i := X509_STORE_add_cert(ctx^.store_ctx, LX);
  1196. if i = 0 then begin
  1197. Exit;
  1198. end;
  1199. Inc(count);
  1200. X509_Free(LX);
  1201. until False;
  1202. Result := count;
  1203. end;
  1204. X509_FILETYPE_ASN1:
  1205. begin
  1206. LX := d2i_X509_bio(Lin, nil);
  1207. if not Assigned(LX) then begin
  1208. X509err(X509_F_X509_LOAD_CERT_FILE, ERR_R_ASN1_LIB);
  1209. Exit;
  1210. end;
  1211. i := X509_STORE_add_cert(ctx^.store_ctx, LX);
  1212. if i = 0 then begin
  1213. Exit;
  1214. end;
  1215. Result := i;
  1216. end;
  1217. else
  1218. X509err(X509_F_X509_LOAD_CERT_FILE, X509_R_BAD_X509_FILETYPE);
  1219. Exit;
  1220. end;
  1221. finally
  1222. BIO_free(Lin);
  1223. end;
  1224. finally
  1225. FreeAndNil(LM);
  1226. end;
  1227. end;
  1228. function Indy_unicode_X509_load_cert_crl_file(ctx: PX509_LOOKUP; const AFileName: String;
  1229. const _type: TIdC_INT): TIdC_INT;
  1230. var
  1231. LM: TMemoryStream;
  1232. Linf: PSTACK_OF_X509_INFO;
  1233. Litmp: PX509_INFO;
  1234. Lin: PBIO;
  1235. i, count: Integer;
  1236. begin
  1237. Result := 0;
  1238. count := 0;
  1239. LM := nil;
  1240. if _type <> X509_FILETYPE_PEM then begin
  1241. Result := Indy_unicode_X509_load_cert_file(ctx, AFileName, _type);
  1242. Exit;
  1243. end;
  1244. try
  1245. LM := TMemoryStream.Create;
  1246. LM.LoadFromFile(AFileName);
  1247. except
  1248. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  1249. // Follow the OpenSSL .DLL Error conventions.
  1250. X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_SYS_LIB);
  1251. LM.Free;
  1252. Exit;
  1253. end;
  1254. try
  1255. Lin := BIO_new_mem_buf(LM.Memory, LM.Size);
  1256. if not Assigned(Lin) then begin
  1257. X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_SYS_LIB);
  1258. Exit;
  1259. end;
  1260. try
  1261. Linf := PEM_X509_INFO_read_bio(Lin, nil, nil, nil);
  1262. finally
  1263. BIO_free(Lin);
  1264. end;
  1265. finally
  1266. FreeAndNil(LM);
  1267. end;
  1268. if not Assigned(Linf) then begin
  1269. X509err(X509_F_X509_LOAD_CERT_CRL_FILE, ERR_R_PEM_LIB);
  1270. Exit;
  1271. end;
  1272. try
  1273. for i := 0 to sk_X509_INFO_num(Linf) - 1 do begin
  1274. Litmp := sk_X509_INFO_value(Linf, i);
  1275. if Assigned(Litmp^.x509) then begin
  1276. X509_STORE_add_cert(ctx^.store_ctx, Litmp^.x509);
  1277. Inc(count);
  1278. end;
  1279. if Assigned(Litmp^.crl) then begin
  1280. X509_STORE_add_crl(ctx^.store_ctx, Litmp^.crl);
  1281. Inc(count);
  1282. end;
  1283. end;
  1284. finally
  1285. sk_X509_INFO_pop_free(Linf, @X509_INFO_free);
  1286. end;
  1287. Result := count;
  1288. end;
  1289. procedure IndySSL_load_client_CA_file_err(var VRes: PSTACK_OF_X509_NAME);
  1290. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1291. begin
  1292. if Assigned(VRes) then begin
  1293. sk_X509_NAME_pop_free(VRes, @X509_NAME_free);
  1294. VRes := nil;
  1295. end;
  1296. end;
  1297. function xname_cmp(const a, b: PPX509_NAME): TIdC_INT; cdecl;
  1298. begin
  1299. Result := X509_NAME_cmp(a^, b^);
  1300. end;
  1301. function IndySSL_load_client_CA_file(const AFileName: String): PSTACK_OF_X509_NAME;
  1302. var
  1303. LM: TMemoryStream;
  1304. LB: PBIO;
  1305. Lsk: PSTACK_OF_X509_NAME;
  1306. LX: PX509;
  1307. LXN, LXNDup: PX509_NAME;
  1308. Failed: Boolean;
  1309. begin
  1310. Result := nil;
  1311. Failed := False;
  1312. LX := nil;
  1313. Lsk := sk_X509_NAME_new(@xname_cmp);
  1314. if Assigned(Lsk) then begin
  1315. try
  1316. LM := nil;
  1317. try
  1318. LM := TMemoryStream.Create;
  1319. LM.LoadFromFile(AFileName);
  1320. except
  1321. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  1322. // Follow the OpenSSL .DLL Error conventions.
  1323. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_SYS_LIB);
  1324. LM.Free;
  1325. Exit;
  1326. end;
  1327. try
  1328. LB := BIO_new_mem_buf(LM.Memory, LM.Size);
  1329. if Assigned(LB) then begin
  1330. try
  1331. try
  1332. repeat
  1333. LX := PEM_read_bio_X509(LB, nil, nil, nil);
  1334. if LX = nil then begin
  1335. Break;
  1336. end;
  1337. if not Assigned(Result) then begin
  1338. Result := sk_X509_NAME_new_null;
  1339. if not Assigned(Result) then begin
  1340. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE);
  1341. Failed := True;
  1342. Exit;
  1343. end;
  1344. end;
  1345. LXN := X509_get_subject_name(LX);
  1346. if not Assigned(LXN) then begin
  1347. // error
  1348. IndySSL_load_client_CA_file_err(Result);
  1349. Failed := True;
  1350. Exit;
  1351. end;
  1352. // * check for duplicates */
  1353. LXNDup := X509_NAME_dup(LXN);
  1354. if not Assigned(LXNDup) then begin
  1355. // error
  1356. IndySSL_load_client_CA_file_err(Result);
  1357. Failed := True;
  1358. Exit;
  1359. end;
  1360. if (sk_X509_NAME_find(Lsk, LXNDup) >= 0) then begin
  1361. X509_NAME_free(LXNDup);
  1362. end else begin
  1363. sk_X509_NAME_push(Lsk, LXNDup);
  1364. sk_X509_NAME_push(Result, LXNDup);
  1365. end;
  1366. X509_free(LX);
  1367. LX := nil;
  1368. until False;
  1369. finally
  1370. if Assigned(LX) then begin
  1371. X509_free(LX);
  1372. end;
  1373. if Failed and Assigned(Result) then begin
  1374. sk_X509_NAME_pop_free(Result, @X509_NAME_free);
  1375. Result := nil;
  1376. end;
  1377. end;
  1378. finally
  1379. BIO_free(LB);
  1380. end;
  1381. end
  1382. else begin
  1383. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE);
  1384. end;
  1385. finally
  1386. FreeAndNil(LM);
  1387. end;
  1388. finally
  1389. sk_X509_NAME_free(Lsk);
  1390. end;
  1391. end
  1392. else begin
  1393. SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE);
  1394. end;
  1395. if Assigned(Result) then begin
  1396. ERR_clear_error;
  1397. end;
  1398. end;
  1399. function IndySSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const AFileName: String;
  1400. AType: Integer): TIdC_INT;
  1401. var
  1402. LM: TMemoryStream;
  1403. B: PBIO;
  1404. LKey: PEVP_PKEY;
  1405. j: TIdC_INT;
  1406. begin
  1407. Result := 0;
  1408. LM := nil;
  1409. try
  1410. LM := TMemoryStream.Create;
  1411. LM.LoadFromFile(AFileName);
  1412. except
  1413. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  1414. // Follow the OpenSSL .DLL Error conventions.
  1415. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_SYS_LIB);
  1416. LM.Free;
  1417. Exit;
  1418. end;
  1419. try
  1420. B := BIO_new_mem_buf(LM.Memory, LM.Size);
  1421. if not Assigned(B) then begin
  1422. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_BUF_LIB);
  1423. Exit;
  1424. end;
  1425. try
  1426. case AType of
  1427. SSL_FILETYPE_PEM:
  1428. begin
  1429. j := ERR_R_PEM_LIB;
  1430. LKey := PEM_read_bio_PrivateKey(B, nil,
  1431. ctx^.default_passwd_callback,
  1432. ctx^.default_passwd_callback_userdata);
  1433. end;
  1434. SSL_FILETYPE_ASN1:
  1435. begin
  1436. j := ERR_R_ASN1_LIB;
  1437. LKey := d2i_PrivateKey_bio(B, nil);
  1438. end;
  1439. else
  1440. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, SSL_R_BAD_SSL_FILETYPE);
  1441. Exit;
  1442. end;
  1443. if not Assigned(LKey) then begin
  1444. SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, j);
  1445. Exit;
  1446. end;
  1447. Result := SSL_CTX_use_PrivateKey(ctx, LKey);
  1448. EVP_PKEY_free(LKey);
  1449. finally
  1450. BIO_free(B);
  1451. end;
  1452. finally
  1453. FreeAndNil(LM);
  1454. end;
  1455. end;
  1456. function IndySSL_CTX_use_certificate_file(ctx: PSSL_CTX;
  1457. const AFileName: String; AType: Integer): TIdC_INT;
  1458. var
  1459. LM: TMemoryStream;
  1460. B: PBIO;
  1461. LX: PX509;
  1462. j: TIdC_INT;
  1463. begin
  1464. Result := 0;
  1465. LM := nil;
  1466. try
  1467. LM := TMemoryStream.Create;
  1468. LM.LoadFromFile(AFileName);
  1469. except
  1470. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  1471. // Follow the OpenSSL .DLL Error conventions.
  1472. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_SYS_LIB);
  1473. LM.Free;
  1474. Exit;
  1475. end;
  1476. try
  1477. B := BIO_new_mem_buf(LM.Memory, LM.Size);
  1478. if not Assigned(B) then begin
  1479. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB);
  1480. Exit;
  1481. end;
  1482. try
  1483. case AType of
  1484. SSL_FILETYPE_ASN1:
  1485. begin
  1486. j := ERR_R_ASN1_LIB;
  1487. LX := d2i_X509_bio(B, nil);
  1488. end;
  1489. SSL_FILETYPE_PEM:
  1490. begin
  1491. j := ERR_R_PEM_LIB;
  1492. LX := PEM_read_bio_X509(B, nil, ctx^.default_passwd_callback,
  1493. ctx^.default_passwd_callback_userdata);
  1494. end
  1495. else begin
  1496. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, SSL_R_BAD_SSL_FILETYPE);
  1497. Exit;
  1498. end;
  1499. end;
  1500. if not Assigned(LX) then begin
  1501. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, j);
  1502. Exit;
  1503. end;
  1504. Result := SSL_CTX_use_certificate(ctx, LX);
  1505. X509_free(LX);
  1506. finally
  1507. BIO_free(B);
  1508. end;
  1509. finally
  1510. FreeAndNil(LM);
  1511. end;
  1512. end;
  1513. function IndySSL_CTX_use_certificate_chain_file(ctx :PSSL_CTX;
  1514. const AFileName: String) : TIdC_INT;
  1515. var
  1516. LM: TMemoryStream;
  1517. B: PBIO;
  1518. LX: PX509;
  1519. ca :PX509;
  1520. r: TIdC_INT;
  1521. LErr :TIdC_ULONG;
  1522. begin
  1523. Result := 0;
  1524. ERR_clear_error(); //* clear error stack for
  1525. //* SSL_CTX_use_certificate() */
  1526. LM := nil;
  1527. try
  1528. LM := TMemoryStream.Create;
  1529. LM.LoadFromFile(AFileName);
  1530. except
  1531. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  1532. // Follow the OpenSSL .DLL Error conventions.
  1533. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_SYS_LIB);
  1534. LM.Free;
  1535. Exit;
  1536. end;
  1537. try
  1538. B := BIO_new_mem_buf(LM.Memory, LM.Size);
  1539. if not Assigned(B) then begin
  1540. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_BUF_LIB);
  1541. Exit;
  1542. end;
  1543. try
  1544. LX := PEM_read_bio_X509_AUX(B, nil, ctx^.default_passwd_callback,
  1545. ctx^.default_passwd_callback_userdata);
  1546. if (Lx = nil) then begin
  1547. SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_CHAIN_FILE, ERR_R_PEM_LIB);
  1548. end else begin
  1549. Result := SSL_CTX_use_certificate(ctx, Lx);
  1550. if (ERR_peek_error() <> 0) then begin
  1551. Result := 0; //* Key/certificate mismatch doesn't imply
  1552. //* ret==0 ... */
  1553. end;
  1554. if Result <> 0 then begin
  1555. SSL_CTX_clear_chain_certs(ctx);
  1556. repeat
  1557. ca := PEM_read_bio_X509(B, nil,
  1558. ctx^.default_passwd_callback,
  1559. ctx^.default_passwd_callback_userdata);
  1560. if ca = nil then begin
  1561. break;
  1562. end;
  1563. r := SSL_CTX_add0_chain_cert(ctx, ca);
  1564. if (r = 0) then begin
  1565. X509_free(ca);
  1566. Result := 0;
  1567. break;
  1568. // goto end;
  1569. end;
  1570. //*
  1571. //* Note that we must not free r if it was successfully added to
  1572. //* the chain (while we must free the main certificate, since its
  1573. //* reference count is increased by SSL_CTX_use_certificate).
  1574. // */
  1575. until False;
  1576. if ca <> nil then begin
  1577. //* When the while loop ends, it's usually just EOF. */
  1578. LErr := ERR_peek_last_error();
  1579. if (ERR_GET_LIB(Lerr) = ERR_LIB_PEM)
  1580. and (ERR_GET_REASON(Lerr) = PEM_R_NO_START_LINE) then begin
  1581. ERR_clear_error();
  1582. end else begin
  1583. Result := 0; //* some real error */
  1584. end;
  1585. end;
  1586. end;
  1587. //err:
  1588. if LX <> nil then begin
  1589. X509_free(LX);
  1590. end;
  1591. end;
  1592. finally
  1593. BIO_free(B);
  1594. end;
  1595. finally
  1596. FreeAndNil(LM);
  1597. end;
  1598. end;
  1599. function IndyX509_STORE_load_locations(ctx: PX509_STORE;
  1600. const AFileName, APathName: String): TIdC_INT;
  1601. var
  1602. lookup: PX509_LOOKUP;
  1603. begin
  1604. Result := 0;
  1605. if AFileName <> '' then begin
  1606. lookup := X509_STORE_add_lookup(ctx, Indy_Unicode_X509_LOOKUP_file);
  1607. if not Assigned(lookup) then begin
  1608. Exit;
  1609. end;
  1610. // RLebeau: the PAnsiChar(Pointer(...)) cast below looks weird, but it is
  1611. // intentional. X509_LOOKUP_load_file() takes a PAnsiChar as input, but
  1612. // we are using Unicode strings here. So casting the UnicodeString to a
  1613. // raw Pointer and then passing that to X509_LOOKUP_load_file() as PAnsiChar.
  1614. // Indy_Unicode_X509_LOOKUP_file will cast it back to PWideChar for processing...
  1615. if (X509_LOOKUP_load_file(lookup, PAnsiChar(Pointer(AFileName)), X509_FILETYPE_PEM) <> 1) then begin
  1616. Exit;
  1617. end;
  1618. end;
  1619. if APathName <> '' then begin
  1620. { TODO: Figure out how to do the hash dir lookup with a Unicode path. }
  1621. if (X509_STORE_load_locations(ctx, nil, PAnsiChar(AnsiString(APathName))) <> 1) then begin
  1622. Exit;
  1623. end;
  1624. end;
  1625. if (AFileName = '') and (APathName = '') then begin
  1626. Exit;
  1627. end;
  1628. Result := 1;
  1629. end;
  1630. function IndySSL_CTX_load_verify_locations(ctx: PSSL_CTX;
  1631. const ACAFile, ACAPath: String): TIdC_INT;
  1632. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1633. begin
  1634. Result := IndyX509_STORE_load_locations(ctx^.cert_store, ACAFile, ACAPath);
  1635. end;
  1636. function IndySSL_CTX_use_DHparams_file(ctx: PSSL_CTX;
  1637. const AFileName: String; AType: Integer): TIdC_INT;
  1638. var
  1639. LM: TMemoryStream;
  1640. B: PBIO;
  1641. LDH: PDH;
  1642. j: Integer;
  1643. begin
  1644. Result := 0;
  1645. LM := nil;
  1646. try
  1647. LM := TMemoryStream.Create;
  1648. LM.LoadFromFile(AFileName);
  1649. except
  1650. // Surpress exception here since it's going to be called by the OpenSSL .DLL
  1651. // Follow the OpenSSL .DLL Error conventions.
  1652. SSLerr(SSL_F_SSL3_CTRL, ERR_R_SYS_LIB);
  1653. LM.Free;
  1654. Exit;
  1655. end;
  1656. try
  1657. B := BIO_new_mem_buf(LM.Memory, LM.Size);
  1658. if not Assigned(B) then begin
  1659. SSLerr(SSL_F_SSL3_CTRL, ERR_R_BUF_LIB);
  1660. Exit;
  1661. end;
  1662. try
  1663. case AType of
  1664. // TODO
  1665. {
  1666. SSL_FILETYPE_ASN1:
  1667. begin
  1668. j := ERR_R_ASN1_LIB;
  1669. LDH := d2i_DHparams_bio(B, nil);
  1670. end;
  1671. }
  1672. SSL_FILETYPE_PEM:
  1673. begin
  1674. j := ERR_R_DH_LIB;
  1675. LDH := PEM_read_bio_DHparams(B, nil, ctx^.default_passwd_callback,
  1676. ctx^.default_passwd_callback_userdata);
  1677. end
  1678. else begin
  1679. SSLerr(SSL_F_SSL3_CTRL, SSL_R_BAD_SSL_FILETYPE);
  1680. Exit;
  1681. end;
  1682. end;
  1683. if not Assigned(LDH) then begin
  1684. SSLerr(SSL_F_SSL3_CTRL, j);
  1685. Exit;
  1686. end;
  1687. Result := SSL_CTX_set_tmp_dh(ctx, LDH);
  1688. DH_free(LDH);
  1689. finally
  1690. BIO_free(B);
  1691. end;
  1692. finally
  1693. FreeAndNil(LM);
  1694. end;
  1695. end;
  1696. {$ENDIF} // WINDOWS
  1697. {$IFDEF UNIX}
  1698. function IndySSL_load_client_CA_file(const AFileName: String) : PSTACK_OF_X509_NAME;
  1699. {$IFDEF USE_MARSHALLED_PTRS}
  1700. var
  1701. M: TMarshaller;
  1702. {$ENDIF}
  1703. begin
  1704. Result := SSL_load_client_CA_file(
  1705. {$IFDEF USE_MARSHALLED_PTRS}
  1706. M.AsUtf8(AFileName).ToPointer
  1707. {$ELSE}
  1708. PAnsiChar(UTF8String(AFileName))
  1709. {$ENDIF}
  1710. );
  1711. end;
  1712. function IndySSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const AFileName: String;
  1713. AType: Integer): TIdC_INT;
  1714. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1715. {$IFDEF USE_MARSHALLED_PTRS}
  1716. var
  1717. M: TMarshaller;
  1718. {$ENDIF}
  1719. begin
  1720. Result := SSL_CTX_use_PrivateKey_file(ctx,
  1721. {$IFDEF USE_MARSHALLED_PTRS}
  1722. M.AsUtf8(AFileName).ToPointer
  1723. {$ELSE}
  1724. PAnsiChar(UTF8String(AFileName))
  1725. {$ENDIF}
  1726. , AType);
  1727. end;
  1728. function IndySSL_CTX_use_certificate_file(ctx: PSSL_CTX;
  1729. const AFileName: String; AType: Integer): TIdC_INT;
  1730. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1731. {$IFDEF USE_MARSHALLED_PTRS}
  1732. var
  1733. M: TMarshaller;
  1734. {$ENDIF}
  1735. begin
  1736. Result := SSL_CTX_use_certificate_file(ctx,
  1737. {$IFDEF USE_MARSHALLED_PTRS}
  1738. M.AsUtf8(AFileName).ToPointer
  1739. {$ELSE}
  1740. PAnsiChar(UTF8String(AFileName))
  1741. {$ENDIF}
  1742. , AType);
  1743. end;
  1744. function IndySSL_CTX_use_certificate_chain_file(ctx :PSSL_CTX;
  1745. const AFileName: String) : TIdC_INT;
  1746. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1747. {$IFDEF USE_MARSHALLED_PTRS}
  1748. var
  1749. M: TMarshaller;
  1750. {$ENDIF}
  1751. begin
  1752. Result := SSL_CTX_use_certificate_chain_file(ctx,
  1753. {$IFDEF USE_MARSHALLED_PTRS}
  1754. M.AsUtf8(AFileName).ToPointer
  1755. {$ELSE}
  1756. PAnsiChar(UTF8String(AFileName))
  1757. {$ENDIF});
  1758. end;
  1759. {$IFDEF USE_MARSHALLED_PTRS}
  1760. function AsUtf8OrNil(var M: TMarshaller; const S: String): Pointer;
  1761. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1762. begin
  1763. if S <> '' then begin
  1764. Result := M.AsUtf8(S).ToPointer;
  1765. end else begin
  1766. Result := nil;
  1767. end;
  1768. end;
  1769. {$ENDIF}
  1770. function IndyX509_STORE_load_locations(ctx: PX509_STORE;
  1771. const AFileName, APathName: String): TIdC_INT;
  1772. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1773. {$IFDEF USE_MARSHALLED_PTRS}
  1774. var
  1775. M: TMarshaller;
  1776. {$ENDIF}
  1777. begin
  1778. // RLebeau 4/18/2010: X509_STORE_load_locations() expects nil pointers
  1779. // for unused values, but casting a string directly to a PAnsiChar
  1780. // always produces a non-nil pointer, which causes X509_STORE_load_locations()
  1781. // to fail. Need to cast the string to an intermediate Pointer so the
  1782. // PAnsiChar cast is applied to the raw data and thus can be nil...
  1783. //
  1784. // RLebeau 8/18/2017: TMarshaller also produces a non-nil TPtrWrapper for
  1785. // an empty string, so need to handle nil specially with marshalled
  1786. // strings as well...
  1787. //
  1788. Result := X509_STORE_load_locations(ctx,
  1789. {$IFDEF USE_MARSHALLED_PTRS}
  1790. AsUtf8OrNil(M, AFileName),
  1791. AsUtf8OrNil(M, APathName)
  1792. {$ELSE}
  1793. PAnsiChar(Pointer(UTF8String(AFileName))),
  1794. PAnsiChar(Pointer(UTF8String(APathName)))
  1795. {$ENDIF}
  1796. );
  1797. end;
  1798. function IndySSL_CTX_load_verify_locations(ctx: PSSL_CTX;
  1799. const ACAFile, ACAPath: String): TIdC_INT;
  1800. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1801. begin
  1802. // RLebeau: why are we calling X509_STORE_load_locations() directly
  1803. // instead of just calling SSL_CTX_load_verify_locations() with
  1804. // UTF-8 input?
  1805. //Result := SSL_CTX_load_verify_locations(ctx,
  1806. // {$IFDEF USE_MARSHALLED_PTRS}
  1807. // AsUtf8OrNl(ACAFile),
  1808. // AsUtf8OrNil(ACAPath)
  1809. // {$ELSE}
  1810. // PAnsiChar(Pointer(UTF8String(ACAFile))),
  1811. // PAnsiChar(Pointer(UTF8String(ACAPath)))
  1812. // {$ENDIF}
  1813. //);
  1814. Result := IndyX509_STORE_load_locations(ctx^.cert_store, ACAFile, ACAPath);
  1815. end;
  1816. function IndySSL_CTX_use_DHparams_file(ctx: PSSL_CTX;
  1817. const AFileName: String; AType: Integer): TIdC_INT;
  1818. var
  1819. B: PBIO;
  1820. LDH: PDH;
  1821. j: Integer;
  1822. {$IFDEF USE_MARSHALLED_PTRS}
  1823. M: TMarshaller;
  1824. {$ENDIF}
  1825. begin
  1826. Result := 0;
  1827. B := BIO_new_file(
  1828. {$IFDEF USE_MARSHALLED_PTRS}
  1829. M.AsUtf8(AFileName).ToPointer
  1830. {$ELSE}
  1831. PAnsiChar(UTF8String(AFileName))
  1832. {$ENDIF}
  1833. , 'r');
  1834. if Assigned(B) then begin
  1835. try
  1836. case AType of
  1837. // TODO
  1838. {
  1839. SSL_FILETYPE_ASN1:
  1840. begin
  1841. j := ERR_R_ASN1_LIB;
  1842. LDH := d2i_DHparams_bio(B, nil);
  1843. end;
  1844. }
  1845. SSL_FILETYPE_PEM:
  1846. begin
  1847. j := ERR_R_DH_LIB;
  1848. LDH := PEM_read_bio_DHparams(B, nil, ctx^.default_passwd_callback,
  1849. ctx^.default_passwd_callback_userdata);
  1850. end
  1851. else begin
  1852. SSLerr(SSL_F_SSL3_CTRL, SSL_R_BAD_SSL_FILETYPE);
  1853. Exit;
  1854. end;
  1855. end;
  1856. if not Assigned(LDH) then begin
  1857. SSLerr(SSL_F_SSL3_CTRL, j);
  1858. Exit;
  1859. end;
  1860. Result := SSL_CTX_set_tmp_dh(ctx, LDH);
  1861. DH_free(LDH);
  1862. finally
  1863. BIO_free(B);
  1864. end;
  1865. end;
  1866. end;
  1867. {$ENDIF} // UNIX
  1868. {$ELSE} // STRING_IS_UNICODE
  1869. function IndySSL_load_client_CA_file(const AFileName: String) : PSTACK_OF_X509_NAME;
  1870. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1871. begin
  1872. Result := SSL_load_client_CA_file(PAnsiChar(AFileName));
  1873. end;
  1874. function IndySSL_CTX_use_PrivateKey_file(ctx: PSSL_CTX; const AFileName: String;
  1875. AType: Integer): TIdC_INT;
  1876. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1877. begin
  1878. Result := SSL_CTX_use_PrivateKey_file(ctx, PAnsiChar(AFileName), AType);
  1879. end;
  1880. function IndySSL_CTX_use_certificate_file(ctx: PSSL_CTX;
  1881. const AFileName: String; AType: Integer): TIdC_INT;
  1882. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1883. begin
  1884. Result := SSL_CTX_use_certificate_file(ctx, PAnsiChar(AFileName), AType);
  1885. end;
  1886. function IndySSL_CTX_use_certificate_chain_file(ctx :PSSL_CTX;
  1887. const AFileName: String) : TIdC_INT;
  1888. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1889. begin
  1890. Result := SSL_CTX_use_certificate_chain_file(ctx, PAnsiChar(AFileName));
  1891. end;
  1892. function IndyX509_STORE_load_locations(ctx: PX509_STORE;
  1893. const AFileName, APathName: String): TIdC_INT;
  1894. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1895. begin
  1896. // RLebeau 4/18/2010: X509_STORE_load_locations() expects nil pointers
  1897. // for unused values, but casting a string directly to a PAnsiChar
  1898. // always produces a non-nil pointer, which causes X509_STORE_load_locations()
  1899. // to fail. Need to cast the string to an intermediate Pointer so the
  1900. // PAnsiChar cast is applied to the raw data and thus can be nil...
  1901. //
  1902. Result := X509_STORE_load_locations(ctx,
  1903. PAnsiChar(Pointer(AFileName)),
  1904. PAnsiChar(Pointer(APathName)));
  1905. end;
  1906. function IndySSL_CTX_load_verify_locations(ctx: PSSL_CTX;
  1907. const ACAFile, ACAPath: String): TIdC_INT;
  1908. begin
  1909. // RLebeau 4/18/2010: X509_STORE_load_locations() expects nil pointers
  1910. // for unused values, but casting a string directly to a PAnsiChar
  1911. // always produces a non-nil pointer, which causes X509_STORE_load_locations()
  1912. // to fail. Need to cast the string to an intermediate Pointer so the
  1913. // PAnsiChar cast is applied to the raw data and thus can be nil...
  1914. //
  1915. Result := SSL_CTX_load_verify_locations(ctx,
  1916. PAnsiChar(Pointer(ACAFile)),
  1917. PAnsiChar(Pointer(ACAPath)));
  1918. end;
  1919. function IndySSL_CTX_use_DHparams_file(ctx: PSSL_CTX;
  1920. const AFileName: String; AType: Integer): TIdC_INT;
  1921. var
  1922. B: PBIO;
  1923. LDH: PDH;
  1924. j: Integer;
  1925. begin
  1926. Result := 0;
  1927. B := BIO_new_file(PAnsiChar(AFileName), 'r');
  1928. if Assigned(B) then begin
  1929. try
  1930. case AType of
  1931. // TODO
  1932. {
  1933. SSL_FILETYPE_ASN1:
  1934. begin
  1935. j := ERR_R_ASN1_LIB;
  1936. LDH := d2i_DHparams_bio(B, nil);
  1937. end;
  1938. }
  1939. SSL_FILETYPE_PEM:
  1940. begin
  1941. j := ERR_R_DH_LIB;
  1942. LDH := PEM_read_bio_DHparams(B, nil, ctx^.default_passwd_callback,
  1943. ctx^.default_passwd_callback_userdata);
  1944. end
  1945. else begin
  1946. SSLerr(SSL_F_SSL3_CTRL, SSL_R_BAD_SSL_FILETYPE);
  1947. Exit;
  1948. end;
  1949. end;
  1950. if not Assigned(LDH) then begin
  1951. SSLerr(SSL_F_SSL3_CTRL, j);
  1952. Exit;
  1953. end;
  1954. Result := SSL_CTX_set_tmp_dh(ctx, LDH);
  1955. DH_free(LDH);
  1956. finally
  1957. BIO_free(B);
  1958. end;
  1959. end;
  1960. end;
  1961. {$ENDIF}
  1962. function AddMins(const DT: TDateTime; const Mins: Extended): TDateTime;
  1963. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1964. begin
  1965. Result := DT + Mins / (60 * 24)
  1966. end;
  1967. function AddHrs(const DT: TDateTime; const Hrs: Extended): TDateTime;
  1968. {$IFDEF USE_INLINE} inline; {$ENDIF}
  1969. begin
  1970. Result := DT + Hrs / 24.0;
  1971. end;
  1972. {$IFDEF OPENSSL_SET_MEMORY_FUNCS}
  1973. function IdMalloc(num: UInt32): Pointer cdecl;
  1974. begin
  1975. Result := AllocMem(num);
  1976. end;
  1977. function IdRealloc(addr: Pointer; num: UInt32): Pointer cdecl;
  1978. begin
  1979. Result := addr;
  1980. ReallocMem(Result, num);
  1981. end;
  1982. procedure IdFree(addr: Pointer)cdecl;
  1983. begin
  1984. FreeMem(addr);
  1985. end;
  1986. procedure IdSslCryptoMallocInit;
  1987. // replaces the actual alloc routines
  1988. // this is useful if you are using a memory manager that can report on leaks
  1989. // at shutdown time.
  1990. var
  1991. r: Integer;
  1992. begin
  1993. r := CRYPTO_set_mem_functions(@IdMalloc, @IdRealloc, @IdFree);
  1994. Assert(r <> 0);
  1995. end;
  1996. {$ENDIF}
  1997. {$IFNDEF OPENSSL_NO_BIO}
  1998. procedure DumpCert(AOut: TStrings; AX509: PX509);
  1999. var
  2000. LMem: PBIO;
  2001. LLen : TIdC_INT;
  2002. LBufPtr : PIdAnsiChar;
  2003. begin
  2004. if Assigned(X509_print) then begin
  2005. LMem := BIO_new(BIO_s_mem);
  2006. if LMem <> nil then begin
  2007. try
  2008. X509_print(LMem, AX509);
  2009. LLen := BIO_get_mem_data(LMem, LBufPtr);
  2010. if (LLen > 0) and (LBufPtr <> nil) then begin
  2011. AOut.Text := IndyTextEncoding_UTF8.GetString(
  2012. {$IFNDEF VCL_6_OR_ABOVE}
  2013. // RLebeau: for some reason, Delphi 5 causes a "There is no overloaded
  2014. // version of 'GetString' that can be called with these arguments" compiler
  2015. // error if the PByte type-cast is used, even though GetString() actually
  2016. // expects a PByte as input. Must be a compiler bug, as it compiles fine
  2017. // in Delphi 6. So, converting to TIdBytes until I find a better solution...
  2018. RawToBytes(LBufPtr^, LLen)
  2019. {$ELSE}
  2020. PByte(LBufPtr), LLen
  2021. {$ENDIF}
  2022. );
  2023. end;
  2024. finally
  2025. BIO_free(LMem);
  2026. end;
  2027. end;
  2028. end;
  2029. end;
  2030. {$ELSE}
  2031. procedure DumpCert(AOut: TStrings; AX509: PX509);
  2032. begin
  2033. end;
  2034. {$ENDIF}
  2035. {$IFNDEF WIN32_OR_WIN64}
  2036. procedure _threadid_func(id : PCRYPTO_THREADID) cdecl;
  2037. begin
  2038. if Assigned(CRYPTO_THREADID_set_numeric) then begin
  2039. CRYPTO_THREADID_set_numeric(id, TIdC_ULONG(CurrentThreadId));
  2040. end;
  2041. end;
  2042. function _GetThreadID: TIdC_ULONG; cdecl;
  2043. begin
  2044. // TODO: Verify how well this will work with fibers potentially running from
  2045. // thread to thread or many on the same thread.
  2046. Result := TIdC_ULONG(CurrentThreadId);
  2047. end;
  2048. {$ENDIF}
  2049. procedure SslLockingCallback(mode, n: TIdC_INT; Afile: PIdAnsiChar;
  2050. line: TIdC_INT)cdecl;
  2051. var
  2052. Lock: TIdCriticalSection;
  2053. LList: TIdCriticalSectionList;
  2054. begin
  2055. Assert(CallbackLockList <> nil);
  2056. Lock := nil;
  2057. LList := CallbackLockList.LockList;
  2058. try
  2059. if n < LList.Count then begin
  2060. Lock := {$IFDEF HAS_GENERICS_TList}LList.Items[n]{$ELSE}TIdCriticalSection(LList.Items[n]){$ENDIF};
  2061. end;
  2062. finally
  2063. CallbackLockList.UnlockList;
  2064. end;
  2065. Assert(Lock <> nil);
  2066. if (mode and CRYPTO_LOCK) = CRYPTO_LOCK then begin
  2067. Lock.Acquire;
  2068. end else begin
  2069. Lock.Release;
  2070. end;
  2071. end;
  2072. procedure PrepareOpenSSLLocking;
  2073. var
  2074. i, cnt: Integer;
  2075. Lock: TIdCriticalSection;
  2076. LList: TIdCriticalSectionList;
  2077. begin
  2078. LList := CallbackLockList.LockList;
  2079. try
  2080. cnt := _CRYPTO_num_locks;
  2081. for i := 0 to cnt - 1 do begin
  2082. Lock := TIdCriticalSection.Create;
  2083. try
  2084. LList.Add(Lock);
  2085. except
  2086. Lock.Free;
  2087. raise;
  2088. end;
  2089. end;
  2090. finally
  2091. CallbackLockList.UnlockList;
  2092. end;
  2093. end;
  2094. // Note that I define UCTTime as PASN1_STRING
  2095. function UTCTime2DateTime(UCTTime: PASN1_UTCTIME): TDateTime;
  2096. {$IFDEF USE_INLINE} inline; {$ENDIF}
  2097. var
  2098. year: Word;
  2099. month: Word;
  2100. day: Word;
  2101. hour: Word;
  2102. min: Word;
  2103. sec: Word;
  2104. tz_h: Integer;
  2105. tz_m: Integer;
  2106. begin
  2107. Result := 0;
  2108. if UTC_Time_Decode(UCTTime, year, month, day, hour, min, sec, tz_h, tz_m) > 0 then begin
  2109. Result := EncodeDate(year, month, day) + EncodeTime(hour, min, sec, 0);
  2110. AddMins(Result, tz_m);
  2111. AddHrs(Result, tz_h);
  2112. Result := UTCTimeToLocalTime(Result);
  2113. end;
  2114. end;
  2115. {
  2116. function RSACallback(sslSocket: PSSL; e: Integer; KeyLength: Integer):PRSA; cdecl;
  2117. const
  2118. RSA: PRSA = nil;
  2119. var
  2120. SSLSocket: TSSLWSocket;
  2121. IdSSLSocket: TIdSSLSocket;
  2122. begin
  2123. IdSSLSocket := TIdSSLSocket(IdSslGetAppData(sslSocket));
  2124. if Assigned(IdSSLSocket) then begin
  2125. IdSSLSocket.TriggerSSLRSACallback(KeyLength);
  2126. end;
  2127. Result := RSA_generate_key(KeyLength, RSA_F4, @RSAProgressCallback, ssl);
  2128. end;
  2129. }
  2130. function LogicalAnd(A, B: Integer): Boolean;
  2131. {$IFDEF USE_INLINE} inline; {$ENDIF}
  2132. begin
  2133. Result := (A and B) = B;
  2134. end;
  2135. function BytesToHexString(APtr: Pointer; ALen: Integer): String;
  2136. {$IFDEF USE_INLINE} inline; {$ENDIF}
  2137. var
  2138. i: Integer;
  2139. LPtr: PByte;
  2140. begin
  2141. Result := '';
  2142. LPtr := PByte(APtr);
  2143. for i := 0 to (ALen - 1) do begin
  2144. if i <> 0 then begin
  2145. Result := Result + ':'; { Do not Localize }
  2146. end;
  2147. Result := Result + IndyFormat('%.2x', [LPtr^]);
  2148. Inc(LPtr);
  2149. end;
  2150. end;
  2151. function MDAsString(const AMD: TIdSSLEVP_MD): String;
  2152. {$IFDEF USE_INLINE} inline; {$ENDIF}
  2153. var
  2154. i: Integer;
  2155. begin
  2156. Result := '';
  2157. for i := 0 to AMD.Length - 1 do begin
  2158. if i <> 0 then begin
  2159. Result := Result + ':'; { Do not Localize }
  2160. end;
  2161. Result := Result + IndyFormat('%.2x', [Byte(AMD.MD[i])]);
  2162. { do not localize }
  2163. end;
  2164. end;
  2165. function LoadOpenSSLLibrary: Boolean;
  2166. begin
  2167. Assert(SSLIsLoaded <> nil);
  2168. SSLIsLoaded.Lock;
  2169. try
  2170. if SSLIsLoaded.Value then begin
  2171. Result := True;
  2172. Exit;
  2173. end;
  2174. Result := IdSSLOpenSSLHeaders.Load;
  2175. if not Result then begin
  2176. Exit;
  2177. end;
  2178. {$IFDEF OPENSSL_SET_MEMORY_FUNCS}
  2179. // has to be done before anything that uses memory
  2180. IdSslCryptoMallocInit;
  2181. {$ENDIF}
  2182. // Create locking structures, we need them for callback routines
  2183. Assert(LockInfoCB = nil);
  2184. LockInfoCB := TIdCriticalSection.Create;
  2185. LockPassCB := TIdCriticalSection.Create;
  2186. LockVerifyCB := TIdCriticalSection.Create;
  2187. SSLIsLoaded.Value := True;
  2188. Result := True;
  2189. finally
  2190. SSLIsLoaded.Unlock;
  2191. end;
  2192. end;
  2193. procedure UnLoadOpenSSLLibrary;
  2194. // allow the user to call unload directly?
  2195. // will then need to implement reference count
  2196. {$IFNDEF USE_OBJECT_ARC}
  2197. var
  2198. i: Integer;
  2199. LList: TIdCriticalSectionList;
  2200. {$ENDIF}
  2201. begin
  2202. // ssl was never loaded
  2203. if Assigned(CRYPTO_set_locking_callback) then begin
  2204. CRYPTO_set_locking_callback(nil);
  2205. end;
  2206. CleanupRandom; // <-- RLebeau: why is this here and not in IdSSLOpenSSLHeaders.Unload()?
  2207. IdSSLOpenSSLHeaders.Unload;
  2208. FreeAndNil(LockInfoCB);
  2209. FreeAndNil(LockPassCB);
  2210. FreeAndNil(LockVerifyCB);
  2211. if Assigned(CallbackLockList) then begin
  2212. {$IFDEF USE_OBJECT_ARC}
  2213. CallbackLockList.Clear; // Items are auto-freed
  2214. {$ELSE}
  2215. LList := CallbackLockList.LockList;
  2216. begin
  2217. try
  2218. for i := 0 to LList.Count - 1 do begin
  2219. {$IFDEF HAS_GENERICS_TList}LList.Items[i]{$ELSE}TIdCriticalSection(LList.Items[i]){$ENDIF}.Free;
  2220. end;
  2221. LList.Clear;
  2222. finally
  2223. CallbackLockList.UnlockList;
  2224. end;
  2225. end;
  2226. {$ENDIF}
  2227. FreeAndNil(CallbackLockList);
  2228. end;
  2229. SSLIsLoaded.Value := False;
  2230. end;
  2231. function OpenSSLVersion: string;
  2232. begin
  2233. Result := '';
  2234. // RLebeau 9/7/2015: even if LoadOpenSSLLibrary() fails, _SSLeay_version()
  2235. // might have been loaded OK before the failure occured. LoadOpenSSLLibrary()
  2236. // does not unload ..
  2237. IdSSLOpenSSL.LoadOpenSSLLibrary;
  2238. if Assigned(_SSLeay_version) then begin
  2239. Result := String(_SSLeay_version(SSLEAY_VERSION));
  2240. end;
  2241. end;
  2242. //////////////////////////////////////////////////////
  2243. // TIdSSLOptions
  2244. ///////////////////////////////////////////////////////
  2245. constructor TIdSSLOptions.Create;
  2246. begin
  2247. inherited Create;
  2248. fMethod := DEF_SSLVERSION;
  2249. fSSLVersions := DEF_SSLVERSIONS;
  2250. end;
  2251. procedure TIdSSLOptions.SetMethod(const AValue: TIdSSLVersion);
  2252. begin
  2253. fMethod := AValue;
  2254. if AValue = sslvSSLv23 then begin
  2255. fSSLVersions := [sslvSSLv2,sslvSSLv3,sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2,sslvTLSv1_3];
  2256. end else begin
  2257. fSSLVersions := [AValue];
  2258. end;
  2259. end;
  2260. procedure TIdSSLOptions.SetSSLVersions(const AValue: TIdSSLVersions);
  2261. begin
  2262. fSSLVersions := AValue;
  2263. if fSSLVersions = [sslvSSLv2] then begin
  2264. fMethod := sslvSSLv2;
  2265. end
  2266. else if fSSLVersions = [sslvSSLv3] then begin
  2267. fMethod := sslvSSLv3;
  2268. end
  2269. else if fSSLVersions = [sslvTLSv1] then begin
  2270. fMethod := sslvTLSv1;
  2271. end
  2272. else if fSSLVersions = [sslvTLSv1_1 ] then begin
  2273. fMethod := sslvTLSv1_1;
  2274. end
  2275. else if fSSLVersions = [sslvTLSv1_2 ] then begin
  2276. fMethod := sslvTLSv1_2;
  2277. end
  2278. else if fSSLVersions = [sslvTLSv1_3] then begin
  2279. fMethod := sslvTLSv1_3;
  2280. end
  2281. else begin
  2282. fMethod := sslvSSLv23;
  2283. if sslvSSLv23 in fSSLVersions then begin
  2284. Exclude(fSSLVersions, sslvSSLv23);
  2285. if fSSLVersions = [] then begin
  2286. fSSLVersions := [sslvSSLv2,sslvSSLv3,sslvTLSv1,sslvTLSv1_1,sslvTLSv1_2,sslvTLSv1_3];
  2287. end;
  2288. end;
  2289. end;
  2290. end;
  2291. procedure TIdSSLOptions.AssignTo(Destination: TPersistent);
  2292. var
  2293. LDest: TIdSSLOptions;
  2294. begin
  2295. if Destination is TIdSSLOptions then begin
  2296. LDest := TIdSSLOptions(Destination);
  2297. LDest.RootCertFile := RootCertFile;
  2298. LDest.CertFile := CertFile;
  2299. LDest.KeyFile := KeyFile;
  2300. LDest.DHParamsFile := DHParamsFile;
  2301. LDest.Method := Method;
  2302. LDest.SSLVersions := SSLVersions;
  2303. LDest.Mode := Mode;
  2304. LDest.VerifyMode := VerifyMode;
  2305. LDest.VerifyDepth := VerifyDepth;
  2306. LDest.VerifyDirs := VerifyDirs;
  2307. LDest.CipherList := CipherList;
  2308. end else begin
  2309. inherited AssignTo(Destination);
  2310. end;
  2311. end;
  2312. ///////////////////////////////////////////////////////
  2313. // TIdServerIOHandlerSSLOpenSSL
  2314. ///////////////////////////////////////////////////////
  2315. { TIdServerIOHandlerSSLOpenSSL }
  2316. procedure TIdServerIOHandlerSSLOpenSSL.InitComponent;
  2317. begin
  2318. inherited InitComponent;
  2319. fxSSLOptions := TIdSSLOptions_Internal.Create;
  2320. TIdSSLOptions_Internal(fxSSLOptions).Parent := Self;
  2321. end;
  2322. destructor TIdServerIOHandlerSSLOpenSSL.Destroy;
  2323. begin
  2324. FreeAndNil(fxSSLOptions);
  2325. inherited Destroy;
  2326. end;
  2327. procedure TIdServerIOHandlerSSLOpenSSL.Init;
  2328. //see also TIdSSLIOHandlerSocketOpenSSL.Init
  2329. begin
  2330. //ensure Init isn't called twice
  2331. Assert(fSSLContext = nil);
  2332. fSSLContext := TIdSSLContext.Create;
  2333. fSSLContext.Parent := Self;
  2334. fSSLContext.RootCertFile := SSLOptions.RootCertFile;
  2335. fSSLContext.CertFile := SSLOptions.CertFile;
  2336. fSSLContext.KeyFile := SSLOptions.KeyFile;
  2337. fSSLContext.DHParamsFile := SSLOptions.DHParamsFile;
  2338. fSSLContext.fVerifyDepth := SSLOptions.fVerifyDepth;
  2339. fSSLContext.fVerifyMode := SSLOptions.fVerifyMode;
  2340. // fSSLContext.fVerifyFile := SSLOptions.fVerifyFile;
  2341. fSSLContext.fVerifyDirs := SSLOptions.fVerifyDirs;
  2342. fSSLContext.fCipherList := SSLOptions.fCipherList;
  2343. fSSLContext.VerifyOn := Assigned(fOnVerifyPeer);
  2344. fSSLContext.StatusInfoOn := Assigned(fOnStatusInfo) or Assigned(FOnStatusInfoEx);
  2345. //fSSLContext.PasswordRoutineOn := Assigned(fOnGetPassword);
  2346. fSSLContext.fMethod := SSLOptions.Method;
  2347. fSSLContext.fMode := SSLOptions.Mode;
  2348. fSSLContext.fSSLVersions := SSLOptions.SSLVersions;
  2349. fSSLContext.InitContext(sslCtxServer);
  2350. end;
  2351. function TIdServerIOHandlerSSLOpenSSL.Accept(ASocket: TIdSocketHandle;
  2352. // This is a thread and not a yarn. Its the listener thread.
  2353. AListenerThread: TIdThread; AYarn: TIdYarn ): TIdIOHandler;
  2354. var
  2355. LIO: TIdSSLIOHandlerSocketOpenSSL;
  2356. begin
  2357. //using a custom scheduler, AYarn may be nil, so don't assert
  2358. Assert(ASocket<>nil);
  2359. Assert(fSSLContext<>nil);
  2360. Assert(AListenerThread<>nil);
  2361. Result := nil;
  2362. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  2363. try
  2364. LIO.PassThrough := True;
  2365. LIO.Open;
  2366. while not AListenerThread.Stopped do begin
  2367. if ASocket.Select(250) then begin
  2368. if (not AListenerThread.Stopped) and LIO.Binding.Accept(ASocket.Handle) then begin
  2369. //we need to pass the SSLOptions for the socket from the server
  2370. // TODO: wouldn't it be easier to just Assign() the server's SSLOptions
  2371. // here? Do we really need to share ownership of it?
  2372. // LIO.fxSSLOptions.Assign(fxSSLOptions);
  2373. FreeAndNil(LIO.fxSSLOptions);
  2374. LIO.IsPeer := True;
  2375. LIO.fxSSLOptions := fxSSLOptions;
  2376. LIO.fSSLSocket := TIdSSLSocket.Create(Self);
  2377. LIO.fSSLContext := fSSLContext;
  2378. // TODO: to enable server-side SNI, we need to:
  2379. // - Set up an additional SSL_CTX for each different certificate;
  2380. // - Add a servername callback to each SSL_CTX using SSL_CTX_set_tlsext_servername_callback();
  2381. // - In the callback, retrieve the client-supplied servername with
  2382. // SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name). Figure out the right
  2383. // SSL_CTX to go with that host name, then switch the SSL object to that
  2384. // SSL_CTX with SSL_set_SSL_CTX().
  2385. // RLebeau 2/1/2022: note, the following call is basically a no-op for OpenSSL,
  2386. // because PassThrough=True and fSSLContext are both assigned above, so there
  2387. // is really nothing for TIdSSLIOHandlerSocketOpenSSL.Init() or
  2388. // TIdSSLIOHandlerSocketOpenSSL.StartSSL() to do when called by
  2389. // TIdSSLIOHandlerSocketOpenSSL.AfterAccept(). If anything, all this will
  2390. // really do is update the Binding's IPVersion. But, calling this is consistent
  2391. // with other server Accept() implementations, so we should do it here, too...
  2392. LIO.AfterAccept;
  2393. Result := LIO;
  2394. LIO := nil;
  2395. Break;
  2396. end;
  2397. end;
  2398. end;
  2399. finally
  2400. FreeAndNil(LIO);
  2401. end;
  2402. end;
  2403. procedure TIdServerIOHandlerSSLOpenSSL.DoStatusInfo(const AMsg: String);
  2404. begin
  2405. if Assigned(fOnStatusInfo) then begin
  2406. fOnStatusInfo(AMsg);
  2407. end;
  2408. end;
  2409. procedure TIdServerIOHandlerSSLOpenSSL.DoStatusInfoEx(const AsslSocket: PSSL;
  2410. const AWhere, Aret: TIdC_INT; const AWhereStr, ARetStr: String);
  2411. begin
  2412. if Assigned(FOnStatusInfoEx) then begin
  2413. FOnStatusInfoEx(Self,AsslSocket,AWhere,Aret,AWHereStr,ARetStr);
  2414. end;
  2415. end;
  2416. procedure TIdServerIOHandlerSSLOpenSSL.DoGetPassword(var Password: String);
  2417. begin
  2418. if Assigned(fOnGetPassword) then begin
  2419. fOnGetPassword(Password);
  2420. end;
  2421. end;
  2422. procedure TIdServerIOHandlerSSLOpenSSL.DoGetPasswordEx(
  2423. var VPassword: String; const AIsWrite: Boolean);
  2424. begin
  2425. if Assigned(fOnGetPasswordEx) then begin
  2426. fOnGetPasswordEx(Self,VPassword,AIsWrite);
  2427. end;
  2428. end;
  2429. function TIdServerIOHandlerSSLOpenSSL.DoVerifyPeer(Certificate: TIdX509;
  2430. AOk: Boolean; ADepth, AError: Integer): Boolean;
  2431. begin
  2432. Result := True;
  2433. if Assigned(fOnVerifyPeer) then begin
  2434. Result := fOnVerifyPeer(Certificate, AOk, ADepth, AError);
  2435. end;
  2436. end;
  2437. function TIdServerIOHandlerSSLOpenSSL.MakeFTPSvrPort : TIdSSLIOHandlerSocketBase;
  2438. var
  2439. LIO : TIdSSLIOHandlerSocketOpenSSL;
  2440. begin
  2441. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  2442. try
  2443. LIO.PassThrough := True;
  2444. LIO.OnGetPassword := DoGetPassword;
  2445. LIO.OnGetPasswordEx := OnGetPasswordEx;
  2446. LIO.IsPeer := True; // RLebeau 1/24/2019: is this still needed now?
  2447. LIO.SSLOptions.Assign(SSLOptions);
  2448. LIO.SSLOptions.Mode := sslmBoth;{or sslmClient}{doesn't really matter}
  2449. LIO.SSLContext := SSLContext;
  2450. except
  2451. LIO.Free;
  2452. raise;
  2453. end;
  2454. Result := LIO;
  2455. end;
  2456. procedure TIdServerIOHandlerSSLOpenSSL.Shutdown;
  2457. begin
  2458. FreeAndNil(fSSLContext);
  2459. inherited Shutdown;
  2460. end;
  2461. function TIdServerIOHandlerSSLOpenSSL.MakeFTPSvrPasv : TIdSSLIOHandlerSocketBase;
  2462. var
  2463. LIO : TIdSSLIOHandlerSocketOpenSSL;
  2464. begin
  2465. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  2466. try
  2467. LIO.PassThrough := True;
  2468. LIO.OnGetPassword := DoGetPassword;
  2469. LIO.OnGetPasswordEx := OnGetPasswordEx;
  2470. LIO.IsPeer := True;
  2471. LIO.SSLOptions.Assign(SSLOptions);
  2472. LIO.SSLOptions.Mode := sslmBoth;{or sslmServer}
  2473. LIO.SSLContext := nil;
  2474. except
  2475. LIO.Free;
  2476. raise;
  2477. end;
  2478. Result := LIO;
  2479. end;
  2480. { IIdSSLOpenSSLCallbackHelper }
  2481. function TIdServerIOHandlerSSLOpenSSL.GetPassword(const AIsWrite : Boolean): string;
  2482. begin
  2483. DoGetPasswordEx(Result, AIsWrite);
  2484. if Result = '' then begin
  2485. DoGetPassword(Result);
  2486. end;
  2487. end;
  2488. procedure TIdServerIOHandlerSSLOpenSSL.StatusInfo(const ASslSocket: PSSL;
  2489. AWhere, ARet: TIdC_INT; const AStatusStr: string);
  2490. var
  2491. LType, LMsg: string;
  2492. begin
  2493. DoStatusInfo(AStatusStr);
  2494. if Assigned(fOnStatusInfoEx) then begin
  2495. GetStateVars(ASslSocket, AWhere, ARet, LType, LMsg);
  2496. DoStatusInfoEx(ASslSocket, AWhere, ARet, LType, LMsg);
  2497. end;
  2498. end;
  2499. function TIdServerIOHandlerSSLOpenSSL.VerifyPeer(ACertificate: TIdX509;
  2500. AOk: Boolean; ADepth, AError: Integer): Boolean;
  2501. begin
  2502. Result := DoVerifyPeer(ACertificate, AOk, ADepth, AError);
  2503. end;
  2504. function TIdServerIOHandlerSSLOpenSSL.GetIOHandlerSelf: TIdSSLIOHandlerSocketOpenSSL;
  2505. begin
  2506. Result := nil;
  2507. end;
  2508. ///////////////////////////////////////////////////////
  2509. // TIdSSLIOHandlerSocketOpenSSL
  2510. ///////////////////////////////////////////////////////
  2511. function TIdServerIOHandlerSSLOpenSSL.MakeClientIOHandler: TIdSSLIOHandlerSocketBase;
  2512. var
  2513. LIO : TIdSSLIOHandlerSocketOpenSSL;
  2514. begin
  2515. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  2516. try
  2517. LIO.PassThrough := True;
  2518. // LIO.SSLOptions.Free;
  2519. // LIO.SSLOptions := SSLOptions;
  2520. // LIO.SSLContext := SSLContext;
  2521. LIO.SSLOptions.Assign(SSLOptions);
  2522. // LIO.SSLContext := SSLContext;
  2523. LIO.SSLContext := nil;//SSLContext.Clone; // BGO: clone does not work, it must be either NIL, or SSLContext
  2524. LIO.OnGetPassword := DoGetPassword;
  2525. LIO.OnGetPasswordEx := OnGetPasswordEx;
  2526. except
  2527. LIO.Free;
  2528. raise;
  2529. end;
  2530. Result := LIO;
  2531. end;
  2532. { TIdSSLIOHandlerSocketOpenSSL }
  2533. procedure TIdSSLIOHandlerSocketOpenSSL.InitComponent;
  2534. begin
  2535. inherited InitComponent;
  2536. IsPeer := False;
  2537. fxSSLOptions := TIdSSLOptions_Internal.Create;
  2538. TIdSSLOptions_Internal(fxSSLOptions).Parent := Self;
  2539. fSSLLayerClosed := True;
  2540. fSSLContext := nil;
  2541. end;
  2542. destructor TIdSSLIOHandlerSocketOpenSSL.Destroy;
  2543. begin
  2544. FreeAndNil(fSSLSocket);
  2545. //we do not destroy these if their Parent is not Self
  2546. //because these do not belong to us when we are in a server.
  2547. if (fSSLContext <> nil) and (fSSLContext.Parent = Self) then begin
  2548. FreeAndNil(fSSLContext);
  2549. end;
  2550. if (fxSSLOptions <> nil) and
  2551. (fxSSLOptions is TIdSSLOptions_Internal) and
  2552. (TIdSSLOptions_Internal(fxSSLOptions).Parent = Self) then
  2553. begin
  2554. FreeAndNil(fxSSLOptions);
  2555. end;
  2556. inherited Destroy;
  2557. end;
  2558. procedure TIdSSLIOHandlerSocketOpenSSL.ConnectClient;
  2559. var
  2560. LPassThrough: Boolean;
  2561. begin
  2562. // RLebeau: initialize OpenSSL before connecting the socket...
  2563. try
  2564. Init;
  2565. except
  2566. on EIdOSSLCouldNotLoadSSLLibrary do begin
  2567. if not PassThrough then raise;
  2568. end;
  2569. end;
  2570. // RLebeau 1/11/07: In case a proxy is being used, pass through
  2571. // any data from the base class unencrypted when setting up that
  2572. // connection. We should do this anyway since SSL hasn't been
  2573. // negotiated yet!
  2574. LPassThrough := fPassThrough;
  2575. fPassThrough := True;
  2576. try
  2577. inherited ConnectClient;
  2578. finally
  2579. fPassThrough := LPassThrough;
  2580. end;
  2581. DoBeforeConnect(Self);
  2582. // CreateSSLContext(sslmClient);
  2583. // CreateSSLContext(SSLOptions.fMode);
  2584. StartSSL;
  2585. end;
  2586. procedure TIdSSLIOHandlerSocketOpenSSL.StartSSL;
  2587. begin
  2588. if not PassThrough then begin
  2589. OpenEncodedConnection;
  2590. end;
  2591. end;
  2592. procedure TIdSSLIOHandlerSocketOpenSSL.Close;
  2593. begin
  2594. FreeAndNil(fSSLSocket);
  2595. if fSSLContext <> nil then begin
  2596. if fSSLContext.Parent = Self then begin
  2597. FreeAndNil(fSSLContext);
  2598. end else begin
  2599. fSSLContext := nil;
  2600. end;
  2601. end;
  2602. inherited Close;
  2603. end;
  2604. procedure TIdSSLIOHandlerSocketOpenSSL.Open;
  2605. begin
  2606. FOpened := False;
  2607. inherited Open;
  2608. end;
  2609. function TIdSSLIOHandlerSocketOpenSSL.Readable(AMSec: Integer = IdTimeoutDefault): Boolean;
  2610. begin
  2611. if not fPassThrough then
  2612. begin
  2613. Result := (fSSLSocket <> nil) and (ssl_pending(fSSLSocket.fSSL) > 0);
  2614. if Result then Exit;
  2615. end;
  2616. Result := inherited Readable(AMSec);
  2617. end;
  2618. procedure TIdSSLIOHandlerSocketOpenSSL.SetPassThrough(const Value: Boolean);
  2619. begin
  2620. if fPassThrough <> Value then begin
  2621. if not Value then begin
  2622. if BindingAllocated then begin
  2623. if Assigned(fSSLContext) then begin
  2624. OpenEncodedConnection;
  2625. end else begin
  2626. raise EIdOSSLCouldNotLoadSSLLibrary.Create(RSOSSLCouldNotLoadSSLLibrary);
  2627. end;
  2628. end;
  2629. end
  2630. else begin
  2631. // RLebeau 8/16/2019: need to call SSL_shutdown() here if the SSL/TLS session is active.
  2632. // This is for FTP when handling CCC and REIN commands. The SSL/TLS session needs to be
  2633. // shutdown cleanly on both ends without closing the underlying socket connection because
  2634. // it is going to be used for continued unsecure communications!
  2635. if (fSSLSocket <> nil) and (fSSLSocket.fSSL <> nil) then begin
  2636. // if SSL_shutdown() returns 0, a "close notify" was sent to the peer and SSL_shutdown()
  2637. // needs to be called again to receive the peer's "close notify" in response...
  2638. if SSL_shutdown(fSSLSocket.fSSL) = 0 then begin
  2639. SSL_shutdown(fSSLSocket.fSSL);
  2640. end;
  2641. end;
  2642. {$IFDEF WIN32_OR_WIN64}
  2643. // begin bug fix
  2644. if BindingAllocated and IndyCheckWindowsVersion(6) then
  2645. begin
  2646. // disables Vista+ SSL_Read and SSL_Write timeout fix
  2647. Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVTIMEO, 0);
  2648. Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_SNDTIMEO, 0);
  2649. end;
  2650. // end bug fix
  2651. {$ENDIF}
  2652. end;
  2653. fPassThrough := Value;
  2654. end;
  2655. end;
  2656. function TIdSSLIOHandlerSocketOpenSSL.RecvEnc(var VBuffer: TIdBytes): Integer;
  2657. begin
  2658. Result := fSSLSocket.Recv(VBuffer);
  2659. end;
  2660. function TIdSSLIOHandlerSocketOpenSSL.SendEnc(const ABuffer: TIdBytes;
  2661. const AOffset, ALength: Integer): Integer;
  2662. begin
  2663. Result := fSSLSocket.Send(ABuffer, AOffset, ALength);
  2664. end;
  2665. procedure TIdSSLIOHandlerSocketOpenSSL.AfterAccept;
  2666. begin
  2667. try
  2668. inherited AfterAccept;
  2669. // RLebeau: initialize OpenSSL after accepting a client socket...
  2670. try
  2671. Init;
  2672. except
  2673. on EIdOSSLCouldNotLoadSSLLibrary do begin
  2674. if not PassThrough then raise;
  2675. end;
  2676. end;
  2677. StartSSL;
  2678. except
  2679. Close;
  2680. raise;
  2681. end;
  2682. end;
  2683. procedure TIdSSLIOHandlerSocketOpenSSL.Init;
  2684. //see also TIdServerIOHandlerSSLOpenSSL.Init
  2685. begin
  2686. if not Assigned(fSSLContext) then begin
  2687. fSSLContext := TIdSSLContext.Create;
  2688. fSSLContext.Parent := Self;
  2689. fSSLContext.RootCertFile := SSLOptions.RootCertFile;
  2690. fSSLContext.CertFile := SSLOptions.CertFile;
  2691. fSSLContext.KeyFile := SSLOptions.KeyFile;
  2692. fSSLContext.DHParamsFile := SSLOptions.DHParamsFile;
  2693. fSSLContext.fVerifyDepth := SSLOptions.fVerifyDepth;
  2694. fSSLContext.fVerifyMode := SSLOptions.fVerifyMode;
  2695. // fSSLContext.fVerifyFile := SSLOptions.fVerifyFile;
  2696. fSSLContext.fVerifyDirs := SSLOptions.fVerifyDirs;
  2697. fSSLContext.fCipherList := SSLOptions.fCipherList;
  2698. fSSLContext.VerifyOn := Assigned(fOnVerifyPeer);
  2699. fSSLContext.StatusInfoOn := Assigned(fOnStatusInfo) or Assigned(fOnStatusInfoEx);
  2700. //fSSLContext.PasswordRoutineOn := Assigned(fOnGetPassword);
  2701. fSSLContext.fMethod := SSLOptions.Method;
  2702. fSSLContext.fSSLVersions := SSLOptions.SSLVersions;
  2703. fSSLContext.fMode := SSLOptions.Mode;
  2704. fSSLContext.InitContext(sslCtxClient);
  2705. end;
  2706. end;
  2707. //}
  2708. procedure TIdSSLIOHandlerSocketOpenSSL.DoStatusInfo(const AMsg: String);
  2709. begin
  2710. if Assigned(fOnStatusInfo) then begin
  2711. fOnStatusInfo(AMsg);
  2712. end;
  2713. end;
  2714. procedure TIdSSLIOHandlerSocketOpenSSL.DoStatusInfoEx(
  2715. const AsslSocket: PSSL; const AWhere, Aret: TIdC_INT; const AWhereStr,
  2716. ARetStr: String);
  2717. begin
  2718. if Assigned(FOnStatusInfoEx) then begin
  2719. FOnStatusInfoEx(Self,AsslSocket,AWhere,Aret,AWHereStr,ARetStr);
  2720. end;
  2721. end;
  2722. procedure TIdSSLIOHandlerSocketOpenSSL.DoGetPassword(var Password: String);
  2723. begin
  2724. if Assigned(fOnGetPassword) then begin
  2725. fOnGetPassword(Password);
  2726. end;
  2727. end;
  2728. procedure TIdSSLIOHandlerSocketOpenSSL.DoGetPasswordEx(var VPassword: String;
  2729. const AIsWrite: Boolean);
  2730. begin
  2731. if Assigned(fOnGetPasswordEx) then begin
  2732. fOnGetPasswordEx(Self,VPassword,AIsWrite);
  2733. end;
  2734. end;
  2735. function TIdSSLIOHandlerSocketOpenSSL.DoVerifyPeer(Certificate: TIdX509;
  2736. AOk: Boolean; ADepth, AError: Integer): Boolean;
  2737. begin
  2738. Result := True;
  2739. if Assigned(fOnVerifyPeer) then begin
  2740. Result := fOnVerifyPeer(Certificate, AOk, ADepth, AError);
  2741. end;
  2742. end;
  2743. procedure TIdSSLIOHandlerSocketOpenSSL.OpenEncodedConnection;
  2744. var
  2745. {$IFDEF WIN32_OR_WIN64}
  2746. LTimeout: Integer;
  2747. {$ENDIF}
  2748. LMode: TIdSSLMode;
  2749. LHost: string;
  2750. // TODO: move the following to TIdSSLIOHandlerSocketBase...
  2751. function GetURIHost: string;
  2752. var
  2753. LURI: TIdURI;
  2754. begin
  2755. Result := '';
  2756. if URIToCheck <> '' then
  2757. begin
  2758. LURI := TIdURI.Create(URIToCheck);
  2759. try
  2760. Result := LURI.Host;
  2761. finally
  2762. LURI.Free;
  2763. end;
  2764. end;
  2765. end;
  2766. function GetProxyTargetHost: string;
  2767. var
  2768. // under ARC, convert a weak reference to a strong reference before working with it
  2769. LTransparentProxy, LNextTransparentProxy: TIdCustomTransparentProxy;
  2770. begin
  2771. Result := '';
  2772. // RLebeau: not reading from the property as it will create a
  2773. // default Proxy object if one is not already assigned...
  2774. LTransparentProxy := FTransparentProxy;
  2775. if Assigned(LTransparentProxy) then
  2776. begin
  2777. if LTransparentProxy.Enabled then
  2778. begin
  2779. repeat
  2780. LNextTransparentProxy := LTransparentProxy.ChainedProxy;
  2781. if not Assigned(LNextTransparentProxy) then Break;
  2782. if not LNextTransparentProxy.Enabled then Break;
  2783. LTransparentProxy := LNextTransparentProxy;
  2784. until False;
  2785. Result := LTransparentProxy.Host;
  2786. end;
  2787. end;
  2788. end;
  2789. begin
  2790. Assert(Binding<>nil);
  2791. if not Assigned(fSSLSocket) then begin
  2792. fSSLSocket := TIdSSLSocket.Create(Self);
  2793. end;
  2794. Assert(fSSLSocket.fSSLContext=nil);
  2795. fSSLSocket.fSSLContext := fSSLContext;
  2796. {$IFDEF WIN32_OR_WIN64}
  2797. // begin bug fix
  2798. if IndyCheckWindowsVersion(6) then
  2799. begin
  2800. // Note: Fix needed to allow SSL_Read and SSL_Write to timeout under
  2801. // Vista+ when connection is dropped
  2802. LTimeout := FReadTimeOut;
  2803. if LTimeout <= 0 then begin
  2804. LTimeout := 30000; // 30 seconds
  2805. end;
  2806. Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVTIMEO, LTimeout);
  2807. Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_SNDTIMEO, LTimeout);
  2808. end;
  2809. // end bug fix
  2810. {$ENDIF}
  2811. // RLebeau 7/2/2015: do not rely on IsPeer to decide whether to call Connect()
  2812. // or Accept(). SSLContext.Mode controls whether a client or server method is
  2813. // used to handle the connection, so that same value should be used here as well.
  2814. // A user encountered a scenario where he needed to connect a TIdTCPClient to a
  2815. // TCP server on a hardware device, but run the client's SSLIOHandler as an SSL
  2816. // server because the device was initiating the SSL handshake as an SSL client.
  2817. // IsPeer was not designed to handle that scenario. Setting IsPeer to True
  2818. // allowed Accept() to be called here, but at the cost of causing memory leaks
  2819. // in TIdSSLIOHandlerSocketOpenSSL.Destroy() and TIdSSLIOHandlerSocketOpenSSL.Close()
  2820. // in client components! IsPeer is intended to be set to True only in server
  2821. // components...
  2822. LMode := fSSLContext.Mode;
  2823. if not (LMode in [sslmClient, sslmServer]) then begin
  2824. // Mode must be sslmBoth (or else TIdSSLContext.SetSSLMethod() would have
  2825. // raised an exception), so just fall back to previous behavior for now,
  2826. // until we can figure out a better way to handle this scenario...
  2827. if IsPeer then begin
  2828. LMode := sslmServer;
  2829. end else begin
  2830. LMode := sslmClient;
  2831. end;
  2832. end;
  2833. if LMode = sslmClient then begin
  2834. LHost := GetURIHost;
  2835. if LHost = '' then
  2836. begin
  2837. LHost := GetProxyTargetHost;
  2838. if LHost = '' then begin
  2839. LHost := Self.Host;
  2840. end;
  2841. end;
  2842. fSSLSocket.fHostName := LHost;
  2843. fSSLSocket.Connect(Binding.Handle);
  2844. end else begin
  2845. fSSLSocket.fHostName := '';
  2846. fSSLSocket.Accept(Binding.Handle);
  2847. end;
  2848. fPassThrough := False;
  2849. end;
  2850. procedure TIdSSLIOHandlerSocketOpenSSL.DoBeforeConnect(ASender: TIdSSLIOHandlerSocketOpenSSL);
  2851. begin
  2852. if Assigned(OnBeforeConnect) then begin
  2853. OnBeforeConnect(Self);
  2854. end;
  2855. end;
  2856. // TODO: add an AOwner parameter
  2857. function TIdSSLIOHandlerSocketOpenSSL.Clone: TIdSSLIOHandlerSocketBase;
  2858. var
  2859. LIO : TIdSSLIOHandlerSocketOpenSSL;
  2860. begin
  2861. LIO := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  2862. try
  2863. LIO.SSLOptions.Assign( SSLOptions );
  2864. LIO.OnStatusInfo := DoStatusInfo;
  2865. LIO.OnGetPassword := DoGetPassword;
  2866. LIO.OnGetPasswordEx := OnGetPasswordEx;
  2867. LIO.OnVerifyPeer := DoVerifyPeer;
  2868. LIO.fSSLSocket := TIdSSLSocket.Create(Self);
  2869. except
  2870. LIO.Free;
  2871. raise;
  2872. end;
  2873. Result := LIO;
  2874. end;
  2875. function TIdSSLIOHandlerSocketOpenSSL.CheckForError(ALastResult: Integer): Integer;
  2876. //var
  2877. // err: Integer;
  2878. begin
  2879. if PassThrough then begin
  2880. Result := inherited CheckForError(ALastResult);
  2881. end else begin
  2882. Result := fSSLSocket.GetSSLError(ALastResult);
  2883. if Result = SSL_ERROR_NONE then begin
  2884. Result := 0;
  2885. Exit;
  2886. end;
  2887. if Result = SSL_ERROR_SYSCALL then begin
  2888. Result := inherited CheckForError(Integer(Id_SOCKET_ERROR));
  2889. Exit;
  2890. end;
  2891. EIdOpenSSLAPISSLError.RaiseExceptionCode(Result, ALastResult, '');
  2892. end;
  2893. end;
  2894. procedure TIdSSLIOHandlerSocketOpenSSL.RaiseError(AError: Integer);
  2895. begin
  2896. if (PassThrough) or (AError = Id_WSAESHUTDOWN) or (AError = Id_WSAECONNABORTED) or (AError = Id_WSAECONNRESET) then begin
  2897. inherited RaiseError(AError);
  2898. end else begin
  2899. EIdOpenSSLAPISSLError.RaiseException(fSSLSocket.fSSL, AError, '');
  2900. end;
  2901. end;
  2902. { IIdSSLOpenSSLCallbackHelper }
  2903. function TIdSSLIOHandlerSocketOpenSSL.GetPassword(const AIsWrite : Boolean): string;
  2904. begin
  2905. DoGetPasswordEx(Result, AIsWrite);
  2906. if Result = '' then begin
  2907. DoGetPassword(Result);
  2908. end;
  2909. end;
  2910. procedure TIdSSLIOHandlerSocketOpenSSL.StatusInfo(const ASslSocket: PSSL;
  2911. AWhere, ARet: TIdC_INT; const AStatusStr: string);
  2912. var
  2913. LType, LMsg: string;
  2914. begin
  2915. DoStatusInfo(AStatusStr);
  2916. if Assigned(fOnStatusInfoEx) then begin
  2917. GetStateVars(ASslSocket, AWhere, ARet, LType, LMsg);
  2918. DoStatusInfoEx(ASslSocket, AWhere, ARet, LType, LMsg);
  2919. end;
  2920. end;
  2921. function TIdSSLIOHandlerSocketOpenSSL.VerifyPeer(ACertificate: TIdX509;
  2922. AOk: Boolean; ADepth, AError: Integer): Boolean;
  2923. begin
  2924. Result := DoVerifyPeer(ACertificate, AOk, ADepth, AError);
  2925. end;
  2926. function TIdSSLIOHandlerSocketOpenSSL.GetIOHandlerSelf: TIdSSLIOHandlerSocketOpenSSL;
  2927. begin
  2928. Result := Self;
  2929. end;
  2930. { TIdSSLContext }
  2931. constructor TIdSSLContext.Create;
  2932. begin
  2933. inherited Create;
  2934. //an exception here probably means that you are using the wrong version
  2935. //of the openssl libraries. refer to comments at the top of this file.
  2936. if not LoadOpenSSLLibrary then begin
  2937. raise EIdOSSLCouldNotLoadSSLLibrary.Create(RSOSSLCouldNotLoadSSLLibrary);
  2938. end;
  2939. fVerifyMode := [];
  2940. fMode := sslmUnassigned;
  2941. fSessionId := 1;
  2942. end;
  2943. destructor TIdSSLContext.Destroy;
  2944. begin
  2945. DestroyContext;
  2946. inherited Destroy;
  2947. end;
  2948. procedure TIdSSLContext.DestroyContext;
  2949. begin
  2950. if fContext <> nil then begin
  2951. SSL_CTX_free(fContext);
  2952. fContext := nil;
  2953. end;
  2954. end;
  2955. procedure TIdSSLContext.InitContext(CtxMode: TIdSSLCtxMode);
  2956. var
  2957. SSLMethod: PSSL_METHOD;
  2958. error: TIdC_INT;
  2959. // pCAname: PSTACK_X509_NAME;
  2960. {$IFDEF USE_MARSHALLED_PTRS}
  2961. M: TMarshaller;
  2962. {$ENDIF}
  2963. begin
  2964. // Destroy the context first
  2965. DestroyContext;
  2966. if fMode = sslmUnassigned then begin
  2967. if CtxMode = sslCtxServer then begin
  2968. fMode := sslmServer;
  2969. end else begin
  2970. fMode := sslmClient;
  2971. end
  2972. end;
  2973. // get SSL method function (SSL2, SSL23, SSL3, TLS)
  2974. SSLMethod := SetSSLMethod;
  2975. // create new SSL context
  2976. fContext := SSL_CTX_new(SSLMethod);
  2977. if fContext = nil then begin
  2978. EIdOSSLCreatingContextError.RaiseException(RSSSLCreatingContextError);
  2979. end;
  2980. //set SSL Versions we will use
  2981. // in OpenSSL 1.0.2g onwards, SSLv2 is disabled and not exported by default
  2982. // at compile-time. If OpenSSL is compiled with "enable-ssl2" enabled so the
  2983. // SSLv2_xxx_method() functions are exported, SSLv2 is still disabled by
  2984. // default in the SSLv23_xxx_method() functions and must be enabled explicitly...
  2985. if IsOpenSSL_SSLv2_Available then begin
  2986. if not (sslvSSLv2 in SSLVersions) then begin
  2987. SSL_CTX_set_options(fContext, SSL_OP_NO_SSLv2);
  2988. end
  2989. else if (fMethod = sslvSSLv23) then begin
  2990. SSL_CTX_clear_options(fContext, SSL_OP_NO_SSLv2);
  2991. end;
  2992. end;
  2993. // SSLv3 might also be disabled as well..
  2994. if IsOpenSSL_SSLv3_Available then begin
  2995. if not (sslvSSLv3 in SSLVersions) then begin
  2996. SSL_CTX_set_options(fContext, SSL_OP_NO_SSLv3);
  2997. end
  2998. else if (fMethod = sslvSSLv23) then begin
  2999. SSL_CTX_clear_options(fContext, SSL_OP_NO_SSLv3);
  3000. end;
  3001. end;
  3002. // may as well do the same for all of them...
  3003. if IsOpenSSL_TLSv1_0_Available then begin
  3004. if not (sslvTLSv1 in SSLVersions) then begin
  3005. SSL_CTX_set_options(fContext, SSL_OP_NO_TLSv1);
  3006. end
  3007. else if (fMethod = sslvSSLv23) then begin
  3008. SSL_CTX_clear_options(fContext, SSL_OP_NO_TLSv1);
  3009. end;
  3010. end;
  3011. {IMPORTANT!!! Do not set SSL_CTX_set_options SSL_OP_NO_TLSv1_1 and
  3012. SSL_OP_NO_TLSv1_2 if that functionality is not available. OpenSSL 1.0 and
  3013. earlier do not support those flags. Those flags would only cause
  3014. an invalid MAC when doing SSL.}
  3015. if IsOpenSSL_TLSv1_1_Available then begin
  3016. if not (sslvTLSv1_1 in SSLVersions) then begin
  3017. SSL_CTX_set_options(fContext, SSL_OP_NO_TLSv1_1);
  3018. end
  3019. else if (fMethod = sslvSSLv23) then begin
  3020. SSL_CTX_clear_options(fContext, SSL_OP_NO_TLSv1_1);
  3021. end;
  3022. end;
  3023. if IsOpenSSL_TLSv1_2_Available then begin
  3024. if not (sslvTLSv1_2 in SSLVersions) then begin
  3025. SSL_CTX_set_options(fContext, SSL_OP_NO_TLSv1_2);
  3026. end
  3027. else if (fMethod = sslvSSLv23) then begin
  3028. SSL_CTX_clear_options(fContext, SSL_OP_NO_TLSv1_2);
  3029. end;
  3030. end;
  3031. if IsOpenSSL_TLSv1_3_Available then begin
  3032. if not(sslvTLSv1_3 in SSLVersions) then begin
  3033. SSL_CTX_set_options(fContext, SSL_OP_NO_TLSv1_3);
  3034. end
  3035. else if (fMethod = sslvSSLv23) then begin
  3036. SSL_CTX_clear_options(fContext, SSL_OP_NO_TLSv1_3);
  3037. end;
  3038. end;
  3039. if sslvTLSv1_3 in SSLVersions then
  3040. SSL_CTX_set_min_proto_version(fContext, TLS1_2_VERSION)
  3041. else if sslvTLSv1_2 in SSLVersions then
  3042. SSL_CTX_set_min_proto_version(fContext, TLS1_2_VERSION)
  3043. else if sslvTLSv1_1 in SSLVersions then
  3044. SSL_CTX_set_min_proto_version(fContext, TLS1_1_VERSION)
  3045. else
  3046. SSL_CTX_set_min_proto_version(fContext, TLS1_VERSION);
  3047. SSL_CTX_set_max_proto_version(fContext, TLS1_3_VERSION);
  3048. SSL_CTX_set_mode(fContext, SSL_MODE_AUTO_RETRY);
  3049. // assign a password lookup routine
  3050. // if PasswordRoutineOn then begin
  3051. SSL_CTX_set_default_passwd_cb(fContext, @PasswordCallback);
  3052. SSL_CTX_set_default_passwd_cb_userdata(fContext, Self);
  3053. // end;
  3054. SSL_CTX_set_default_verify_paths(fContext);
  3055. // load key and certificate files
  3056. if (RootCertFile <> '') or (VerifyDirs <> '') then begin {Do not Localize}
  3057. if not LoadRootCert then begin
  3058. EIdOSSLLoadingRootCertError.RaiseException(RSSSLLoadingRootCertError);
  3059. end;
  3060. end;
  3061. if CertFile <> '' then begin {Do not Localize}
  3062. if not LoadCert then begin
  3063. EIdOSSLLoadingCertError.RaiseException(RSSSLLoadingCertError);
  3064. end;
  3065. end;
  3066. if KeyFile <> '' then begin {Do not Localize}
  3067. if not LoadKey then begin
  3068. EIdOSSLLoadingKeyError.RaiseException(RSSSLLoadingKeyError);
  3069. end;
  3070. end;
  3071. if DHParamsFile <> '' then begin {Do not Localize}
  3072. if not LoadDHParams then begin
  3073. EIdOSSLLoadingDHParamsError.RaiseException(RSSSLLoadingDHParamsError);
  3074. end;
  3075. end;
  3076. if StatusInfoOn then begin
  3077. SSL_CTX_set_info_callback(fContext, InfoCallback);
  3078. end;
  3079. //if_SSL_CTX_set_tmp_rsa_callback(hSSLContext, @RSACallback);
  3080. if fCipherList <> '' then begin {Do not Localize}
  3081. error := SSL_CTX_set_cipher_list(fContext,
  3082. {$IFDEF USE_MARSHALLED_PTRS}
  3083. M.AsAnsi(fCipherList).ToPointer
  3084. {$ELSE}
  3085. PAnsiChar(
  3086. {$IFDEF STRING_IS_ANSI}
  3087. fCipherList
  3088. {$ELSE}
  3089. AnsiString(fCipherList) // explicit cast to Ansi
  3090. {$ENDIF}
  3091. )
  3092. {$ENDIF}
  3093. );
  3094. end else begin
  3095. // RLebeau: don't override OpenSSL's default. As OpenSSL evolves, the
  3096. // SSL_DEFAULT_CIPHER_LIST constant defined in the C/C++ SDK may change,
  3097. // while Indy's define of it might take some time to catch up. We don't
  3098. // want users using an older default with newer DLLs...
  3099. (*
  3100. error := SSL_CTX_set_cipher_list(fContext,
  3101. {$IFDEF USE_MARSHALLED_PTRS}
  3102. M.AsAnsi(SSL_DEFAULT_CIPHER_LIST).ToPointer
  3103. {$ELSE}
  3104. SSL_DEFAULT_CIPHER_LIST
  3105. {$ENDIF}
  3106. );
  3107. *)
  3108. error := 1;
  3109. end;
  3110. if error <= 0 then begin
  3111. // TODO: should this be using EIdOSSLSettingCipherError.RaiseException() instead?
  3112. raise EIdOSSLSettingCipherError.Create(RSSSLSettingCipherError);
  3113. end;
  3114. if fVerifyMode <> [] then begin
  3115. SetVerifyMode(fVerifyMode, VerifyOn);
  3116. end;
  3117. if CtxMode = sslCtxServer then begin
  3118. SSL_CTX_set_session_id_context(fContext, PByte(@fSessionId), SizeOf(fSessionId));
  3119. end;
  3120. // CA list
  3121. if RootCertFile <> '' then begin {Do not Localize}
  3122. SSL_CTX_set_client_CA_list(fContext, IndySSL_load_client_CA_file(RootCertFile));
  3123. end
  3124. // TODO: provide an event so users can apply their own settings as needed...
  3125. end;
  3126. procedure TIdSSLContext.SetVerifyMode(Mode: TIdSSLVerifyModeSet; CheckRoutine: Boolean);
  3127. var
  3128. Func: TSSL_CTX_set_verify_callback;
  3129. begin
  3130. if fContext<>nil then begin
  3131. // SSL_CTX_set_default_verify_paths(fContext);
  3132. if CheckRoutine then begin
  3133. Func := VerifyCallback;
  3134. end else begin
  3135. Func := nil;
  3136. end;
  3137. SSL_CTX_set_verify(fContext, TranslateInternalVerifyToSSL(Mode), Func);
  3138. SSL_CTX_set_verify_depth(fContext, fVerifyDepth);
  3139. end;
  3140. end;
  3141. function TIdSSLContext.GetVerifyMode: TIdSSLVerifyModeSet;
  3142. begin
  3143. Result := fVerifyMode;
  3144. end;
  3145. {
  3146. function TIdSSLContext.LoadVerifyLocations(FileName: String; Dirs: String): Boolean;
  3147. begin
  3148. Result := False;
  3149. if (Dirs <> '') or (FileName <> '') then begin
  3150. if IndySSL_CTX_load_verify_locations(fContext, FileName, Dirs) <= 0 then begin
  3151. raise EIdOSSLCouldNotLoadSSLLibrary.Create(RSOSSLCouldNotLoadSSLLibrary);
  3152. end;
  3153. end;
  3154. Result := True;
  3155. end;
  3156. }
  3157. function SelectTLS1Method(const AMode : TIdSSLMode) : PSSL_METHOD;
  3158. {$IFDEF USE_INLINE} inline; {$ENDIF}
  3159. begin
  3160. Result := nil;
  3161. case AMode of
  3162. sslmServer : begin
  3163. if Assigned(TLSv1_server_method) then begin
  3164. Result := TLSv1_server_method();
  3165. end;
  3166. end;
  3167. sslmClient : begin
  3168. if Assigned(TLSv1_client_method) then begin
  3169. Result := TLSv1_client_method();
  3170. end;
  3171. end;
  3172. else
  3173. if Assigned(TLSv1_method) then begin
  3174. Result := TLSv1_method();
  3175. end;
  3176. end;
  3177. end;
  3178. function TIdSSLContext.SetSSLMethod: PSSL_METHOD;
  3179. begin
  3180. Result := nil;
  3181. if fMode = sslmUnassigned then begin
  3182. raise EIdOSSLModeNotSet.Create(RSOSSLModeNotSet);
  3183. end;
  3184. case fMethod of
  3185. sslvSSLv2:
  3186. case fMode of
  3187. sslmServer : begin
  3188. if Assigned(SSLv2_server_method) then begin
  3189. Result := SSLv2_server_method();
  3190. end;
  3191. end;
  3192. sslmClient : begin
  3193. if Assigned(SSLv2_client_method) then begin
  3194. Result := SSLv2_client_method();
  3195. end;
  3196. end;
  3197. else
  3198. if Assigned(SSLv2_method) then begin
  3199. Result := SSLv2_method();
  3200. end;
  3201. end;
  3202. sslvSSLv23:
  3203. if Assigned(TLS_method) then
  3204. Result := TLS_method()
  3205. else
  3206. Result := SelectTLS1Method(fMode);
  3207. sslvSSLv3:
  3208. case fMode of
  3209. sslmServer : begin
  3210. if Assigned(SSLv3_server_method) then begin
  3211. Result := SSLv3_server_method();
  3212. end;
  3213. end;
  3214. sslmClient : begin
  3215. if Assigned(SSLv3_client_method) then begin
  3216. Result := SSLv3_client_method();
  3217. end;
  3218. end;
  3219. else
  3220. if Assigned(SSLv3_method) then begin
  3221. Result := SSLv3_method();
  3222. end;
  3223. end;
  3224. {IMPORTANT!!! fallback to TLS 1.0 if TLS 1.1 or 1.2 is not available.
  3225. This is important because OpenSSL earlier than 1.0.1 does not support this
  3226. functionality.
  3227. Todo: Figure out a better fallback.
  3228. }
  3229. // TODO: get rid of this fallack! If the user didn't choose TLS 1.0, then
  3230. // don't falback to it, just fail instead, like with all of the other SSL/TLS
  3231. // versions...
  3232. sslvTLSv1:
  3233. Result := SelectTLS1Method(fMode);
  3234. sslvTLSv1_1:
  3235. case fMode of
  3236. sslmServer : begin
  3237. if Assigned(TLSv1_1_server_method) then begin
  3238. Result := TLSv1_1_server_method();
  3239. end else begin
  3240. Result := SelectTLS1Method(fMode);
  3241. end;
  3242. end;
  3243. sslmClient : begin
  3244. if Assigned(TLSv1_1_client_method) then begin
  3245. Result := TLSv1_1_client_method();
  3246. end else begin
  3247. Result := SelectTLS1Method(fMode);
  3248. end;
  3249. end;
  3250. else
  3251. if Assigned(TLSv1_1_method) then begin
  3252. Result := TLSv1_1_method();
  3253. end else begin
  3254. Result := SelectTLS1Method(fMode);
  3255. end;
  3256. end;
  3257. sslvTLSv1_2:
  3258. case fMode of
  3259. sslmServer : begin
  3260. if Assigned(TLSv1_2_server_method) then begin
  3261. Result := TLSv1_2_server_method();
  3262. end else begin
  3263. // TODO: fallback to TLSv1.1 if available?
  3264. Result := SelectTLS1Method(fMode);
  3265. end;
  3266. end;
  3267. sslmClient : begin
  3268. if Assigned(TLSv1_2_client_method) then begin
  3269. Result := TLSv1_2_client_method();
  3270. end else begin
  3271. // TODO: fallback to TLSv1.1 if available?
  3272. Result := SelectTLS1Method(fMode);
  3273. end;
  3274. end;
  3275. else
  3276. if Assigned(TLSv1_2_method) then begin
  3277. Result := TLSv1_2_method();
  3278. end else begin
  3279. // TODO: fallback to TLSv1.1 if available?
  3280. Result := SelectTLS1Method(fMode);
  3281. end;
  3282. end;
  3283. sslvTLSv1_3:
  3284. if Assigned(TLS_method) then
  3285. Result := TLS_method()
  3286. else
  3287. Result := SelectTLS1Method(fMode);
  3288. end;
  3289. if Result = nil then begin
  3290. raise EIdOSSLGetMethodError.Create(RSSSLGetMethodError);
  3291. end;
  3292. end;
  3293. function TIdSSLContext.LoadRootCert: Boolean;
  3294. begin
  3295. Result := IndySSL_CTX_load_verify_locations(fContext, RootCertFile, VerifyDirs) > 0;
  3296. end;
  3297. function TIdSSLContext.LoadCert: Boolean;
  3298. begin
  3299. if PosInStrArray(ExtractFileExt(CertFile), ['.p12', '.pfx'], False) <> -1 then begin
  3300. Result := IndySSL_CTX_use_certificate_file_PKCS12(fContext, CertFile) > 0;
  3301. end else begin
  3302. //OpenSSL 1.0.2 has a new function, SSL_CTX_use_certificate_chain_file
  3303. //that handles a chain of certificates in a PEM file. That is prefered.
  3304. if Assigned(SSL_CTX_use_certificate_chain_file) then begin
  3305. Result := IndySSL_CTX_use_certificate_chain_file(fContext, CertFile) > 0;
  3306. end else begin
  3307. Result := IndySSL_CTX_use_certificate_file(fContext, CertFile, SSL_FILETYPE_PEM) > 0;
  3308. end;
  3309. end;
  3310. end;
  3311. function TIdSSLContext.LoadKey: Boolean;
  3312. begin
  3313. if PosInStrArray(ExtractFileExt(KeyFile), ['.p12', '.pfx'], False) <> -1 then begin
  3314. Result := IndySSL_CTX_use_PrivateKey_file_PKCS12(fContext, KeyFile) > 0;
  3315. end else begin
  3316. Result := IndySSL_CTX_use_PrivateKey_file(fContext, KeyFile, SSL_FILETYPE_PEM) > 0;
  3317. end;
  3318. if Result then begin
  3319. Result := SSL_CTX_check_private_key(fContext) > 0;
  3320. end;
  3321. end;
  3322. function TIdSSLContext.LoadDHParams: Boolean;
  3323. begin
  3324. Result := IndySSL_CTX_use_DHparams_file(fContext, fsDHParamsFile, SSL_FILETYPE_PEM) > 0;
  3325. end;
  3326. //////////////////////////////////////////////////////////////
  3327. function TIdSSLContext.Clone: TIdSSLContext;
  3328. begin
  3329. Result := TIdSSLContext.Create;
  3330. Result.StatusInfoOn := StatusInfoOn;
  3331. // property PasswordRoutineOn: Boolean read fPasswordRoutineOn write fPasswordRoutineOn;
  3332. Result.VerifyOn := VerifyOn;
  3333. Result.Method := Method;
  3334. Result.SSLVersions := SSLVersions;
  3335. Result.Mode := Mode;
  3336. Result.RootCertFile := RootCertFile;
  3337. Result.CertFile := CertFile;
  3338. Result.KeyFile := KeyFile;
  3339. Result.VerifyMode := VerifyMode;
  3340. Result.VerifyDepth := VerifyDepth;
  3341. end;
  3342. { TIdSSLSocket }
  3343. constructor TIdSSLSocket.Create(Parent: TObject);
  3344. begin
  3345. inherited Create;
  3346. fParent := Parent;
  3347. end;
  3348. destructor TIdSSLSocket.Destroy;
  3349. begin
  3350. if fSSL <> nil then begin
  3351. // TODO: should this be moved to TIdSSLContext instead? Is this here
  3352. // just to make sure the SSL shutdown does not log any messages?
  3353. {
  3354. if (fSSLContext <> nil) and (fSSLContext.StatusInfoOn) and
  3355. (fSSLContext.fContext <> nil) then begin
  3356. SSL_CTX_set_info_callback(fSSLContext.fContext, nil);
  3357. end;
  3358. }
  3359. //SSL_set_shutdown(fSSL, SSL_SENT_SHUTDOWN);
  3360. SSL_shutdown(fSSL);
  3361. SSL_free(fSSL);
  3362. fSSL := nil;
  3363. end;
  3364. FreeAndNil(fSSLCipher);
  3365. FreeAndNil(fPeerCert);
  3366. inherited Destroy;
  3367. end;
  3368. function TIdSSLSocket.GetSSLError(retCode: Integer): Integer;
  3369. begin
  3370. // COMMENT!!!
  3371. // I found out that SSL layer should not interpret errors, cause they will pop up
  3372. // on the socket layer. Only thing that the SSL layer should consider is key
  3373. // or protocol renegotiation. This is done by loop in read and write
  3374. Result := SSL_get_error(fSSL, retCode);
  3375. case Result of
  3376. SSL_ERROR_NONE:
  3377. Result := SSL_ERROR_NONE;
  3378. SSL_ERROR_WANT_WRITE:
  3379. Result := SSL_ERROR_WANT_WRITE;
  3380. SSL_ERROR_WANT_READ:
  3381. Result := SSL_ERROR_WANT_READ;
  3382. SSL_ERROR_ZERO_RETURN:
  3383. Result := SSL_ERROR_ZERO_RETURN;
  3384. //Result := SSL_ERROR_NONE;
  3385. {
  3386. // ssl layer has been disconnected, it is not necessary that also
  3387. // socked has been closed
  3388. case Mode of
  3389. sslemClient: begin
  3390. case Action of
  3391. sslWrite: begin
  3392. if retCode = 0 then begin
  3393. Result := 0;
  3394. end
  3395. else begin
  3396. raise EIdException.Create(RSOSSLConnectionDropped); // TODO: create a new Exception class for this
  3397. end;
  3398. end;
  3399. end;
  3400. end;}
  3401. //raise EIdException.Create(RSOSSLConnectionDropped); // TODO: create a new Exception class for this
  3402. // X509_LOOKUP event is not really an error, just an event
  3403. // SSL_ERROR_WANT_X509_LOOKUP:
  3404. // raise EIdException.Create(RSOSSLCertificateLookup); // TODO: create a new Exception class for this
  3405. SSL_ERROR_SYSCALL:
  3406. Result := SSL_ERROR_SYSCALL;
  3407. // Result := SSL_ERROR_NONE;
  3408. {//raise EIdException.Create(RSOSSLInternal); // TODO: create a new Exception class for this
  3409. if (retCode <> 0) or (DataLen <> 0) then begin
  3410. raise EIdException.Create(RSOSSLConnectionDropped); // TODO: create a new Exception class for this
  3411. end
  3412. else begin
  3413. Result := 0;
  3414. end;}
  3415. SSL_ERROR_SSL:
  3416. // raise EIdException.Create(RSOSSLInternal); // TODO: create a new Exception class for this
  3417. Result := SSL_ERROR_SSL;
  3418. // Result := SSL_ERROR_NONE;
  3419. end;
  3420. end;
  3421. procedure TIdSSLSocket.Accept(const pHandle: TIdStackSocketHandle);
  3422. //Accept and Connect have a lot of duplicated code
  3423. var
  3424. error: Integer;
  3425. StatusStr: String;
  3426. LParentIO: TIdSSLIOHandlerSocketOpenSSL;
  3427. LHelper: IIdSSLOpenSSLCallbackHelper;
  3428. begin
  3429. Assert(fSSL=nil);
  3430. Assert(fSSLContext<>nil);
  3431. fSSL := SSL_new(fSSLContext.fContext);
  3432. if fSSL = nil then begin
  3433. raise EIdOSSLCreatingSessionError.Create(RSSSLCreatingSessionError);
  3434. end;
  3435. error := SSL_set_app_data(fSSL, Self);
  3436. if error <= 0 then begin
  3437. EIdOSSLDataBindingError.RaiseException(fSSL, error, RSSSLDataBindingError);
  3438. end;
  3439. error := SSL_set_fd(fSSL, pHandle);
  3440. if error <= 0 then begin
  3441. EIdOSSLFDSetError.RaiseException(fSSL, error, RSSSLFDSetError);
  3442. end;
  3443. // RLebeau: if this socket's IOHandler was cloned, no need to reuse the
  3444. // original IOHandler's active session ID, since this is a server socket
  3445. // that generates its own sessions...
  3446. //
  3447. // RLebeau: is this actually true? Should we be reusing the original
  3448. // IOHandler's active session ID regardless of whether this is a client
  3449. // or server socket? What about FTP in non-passive mode, for example?
  3450. {
  3451. if (LParentIO <> nil) and (LParentIO.fSSLSocket <> nil) and
  3452. (LParentIO.fSSLSocket <> Self) then
  3453. begin
  3454. SSL_copy_session_id(fSSL, LParentIO.fSSLSocket.fSSL);
  3455. end;
  3456. }
  3457. error := SSL_accept(fSSL);
  3458. if error <= 0 then begin
  3459. EIdOSSLAcceptError.RaiseException(fSSL, error, RSSSLAcceptError);
  3460. end;
  3461. if Supports(fParent, IIdSSLOpenSSLCallbackHelper, IInterface(LHelper)) then begin
  3462. LParentIO := LHelper.GetIOHandlerSelf;
  3463. if LParentIO <> nil then begin
  3464. StatusStr := 'Cipher: name = ' + Cipher.Name + '; ' + {Do not Localize}
  3465. 'description = ' + Cipher.Description + '; ' + {Do not Localize}
  3466. 'bits = ' + IntToStr(Cipher.Bits) + '; ' + {Do not Localize}
  3467. 'version = ' + Cipher.Version + '; '; {Do not Localize}
  3468. LParentIO.DoStatusInfo(StatusStr);
  3469. end;
  3470. LHelper := nil;
  3471. end;
  3472. end;
  3473. procedure TIdSSLSocket.Connect(const pHandle: TIdStackSocketHandle);
  3474. var
  3475. error: Integer;
  3476. StatusStr: String;
  3477. LParentIO: TIdSSLIOHandlerSocketOpenSSL;
  3478. LHelper: IIdSSLOpenSSLCallbackHelper;
  3479. begin
  3480. Assert(fSSL=nil);
  3481. Assert(fSSLContext<>nil);
  3482. if Supports(fParent, IIdSSLOpenSSLCallbackHelper, IInterface(LHelper)) then begin
  3483. LParentIO := LHelper.GetIOHandlerSelf;
  3484. end else begin
  3485. LParentIO := nil;
  3486. end;
  3487. fSSL := SSL_new(fSSLContext.fContext);
  3488. if fSSL = nil then begin
  3489. raise EIdOSSLCreatingSessionError.Create(RSSSLCreatingSessionError);
  3490. end;
  3491. error := SSL_set_app_data(fSSL, Self);
  3492. if error <= 0 then begin
  3493. EIdOSSLDataBindingError.RaiseException(fSSL, error, RSSSLDataBindingError);
  3494. end;
  3495. error := SSL_set_fd(fSSL, pHandle);
  3496. if error <= 0 then begin
  3497. EIdOSSLFDSetError.RaiseException(fSSL, error, RSSSLFDSetError);
  3498. end;
  3499. // RLebeau: if this socket's IOHandler was cloned, reuse the
  3500. // original IOHandler's active session ID...
  3501. if (LParentIO <> nil) and (LParentIO.fSSLSocket <> nil) and
  3502. (LParentIO.fSSLSocket <> Self) then
  3503. begin
  3504. SSL_copy_session_id(fSSL, LParentIO.fSSLSocket.fSSL);
  3505. end;
  3506. {$IFNDEF OPENSSL_NO_TLSEXT}
  3507. error := SSL_set_tlsext_host_name(fSSL, fHostName);
  3508. if error <= 0 then begin
  3509. // RLebeau: for the time being, not raising an exception on error, as I don't
  3510. // know which OpenSSL versions support this extension, and which error code(s)
  3511. // are safe to ignore on those versions...
  3512. //EIdOSSLSettingTLSHostNameError.RaiseException(fSSL, error, RSSSLSettingTLSHostNameError);
  3513. end;
  3514. {$ENDIF}
  3515. error := SSL_connect(fSSL);
  3516. if error <= 0 then begin
  3517. // TODO: if sslv23 is being used, but sslv23 is not being used on the
  3518. // remote side, SSL_connect() will fail. In that case, before giving up,
  3519. // try re-connecting using a version-specific method for each enabled
  3520. // version, maybe one will succeed...
  3521. EIdOSSLConnectError.RaiseException(fSSL, error, RSSSLConnectError);
  3522. end;
  3523. // TODO: even if SSL_connect() returns success, the connection might
  3524. // still be insecure if SSL_connect() detected that certificate validation
  3525. // actually failed, but ignored it because SSL_VERIFY_PEER was disabled!
  3526. // It would report such a failure via SSL_get_verify_result() instead of
  3527. // returning an error code, so we should call SSL_get_verify_result() here
  3528. // to make sure...
  3529. if LParentIO <> nil then begin
  3530. StatusStr := 'Cipher: name = ' + Cipher.Name + '; ' + {Do not Localize}
  3531. 'description = ' + Cipher.Description + '; ' + {Do not Localize}
  3532. 'bits = ' + IntToStr(Cipher.Bits) + '; ' + {Do not Localize}
  3533. 'version = ' + Cipher.Version + '; '; {Do not Localize}
  3534. LParentIO.DoStatusInfo(StatusStr);
  3535. end;
  3536. // TODO: enable this
  3537. {
  3538. var
  3539. peercert: PX509;
  3540. lHostName: AnsiString;
  3541. peercert := SSL_get_peer_certificate(fSSL);
  3542. try
  3543. lHostName := AnsiString(fHostName);
  3544. if (X509_check_host(peercert, PByte(PAnsiChar(lHostName)), Length(lHostName), 0) != 1) and
  3545. (not certificate_host_name_override(peercert, PAnsiChar(lHostName)) then
  3546. begin
  3547. EIdOSSLCertificateError.RaiseException(fSSL, error, 'SSL certificate does not match host name');
  3548. end;
  3549. finally
  3550. X509_free(peercert);
  3551. end;
  3552. }
  3553. end;
  3554. function TIdSSLSocket.Recv(var ABuffer: TIdBytes): Integer;
  3555. var
  3556. ret, err: Integer;
  3557. begin
  3558. repeat
  3559. ret := SSL_read(fSSL, PByte(ABuffer), Length(ABuffer));
  3560. if ret > 0 then begin
  3561. Result := ret;
  3562. Exit;
  3563. end;
  3564. err := GetSSLError(ret);
  3565. if (err = SSL_ERROR_WANT_READ) or (err = SSL_ERROR_WANT_WRITE) then begin
  3566. Continue;
  3567. end;
  3568. if err = SSL_ERROR_ZERO_RETURN then begin
  3569. Result := 0;
  3570. end else begin
  3571. Result := ret;
  3572. end;
  3573. Exit;
  3574. until False;
  3575. end;
  3576. function TIdSSLSocket.Send(const ABuffer: TIdBytes; AOffset, ALength: Integer): Integer;
  3577. var
  3578. ret, err: Integer;
  3579. begin
  3580. Result := 0;
  3581. repeat
  3582. ret := SSL_write(fSSL, @ABuffer[AOffset], ALength);
  3583. if ret > 0 then begin
  3584. Inc(Result, ret);
  3585. Inc(AOffset, ret);
  3586. Dec(ALength, ret);
  3587. if ALength < 1 then begin
  3588. Exit;
  3589. end;
  3590. Continue;
  3591. end;
  3592. err := GetSSLError(ret);
  3593. if (err = SSL_ERROR_WANT_READ) or (err = SSL_ERROR_WANT_WRITE) then begin
  3594. Continue;
  3595. end;
  3596. if err = SSL_ERROR_ZERO_RETURN then begin
  3597. Result := 0;
  3598. end else begin
  3599. Result := ret;
  3600. end;
  3601. Exit;
  3602. until False;
  3603. end;
  3604. function TIdSSLSocket.GetPeerCert: TIdX509;
  3605. var
  3606. LX509: PX509;
  3607. begin
  3608. if fPeerCert = nil then begin
  3609. LX509 := SSL_get_peer_certificate(fSSL);
  3610. if LX509 <> nil then begin
  3611. fPeerCert := TIdX509.Create(LX509, False);
  3612. end;
  3613. end;
  3614. Result := fPeerCert;
  3615. end;
  3616. function TIdSSLSocket.GetSSLCipher: TIdSSLCipher;
  3617. begin
  3618. if (fSSLCipher = nil) and (fSSL<>nil) then begin
  3619. fSSLCipher := TIdSSLCipher.Create(Self);
  3620. end;
  3621. Result := fSSLCipher;
  3622. end;
  3623. function TIdSSLSocket.GetSessionID: TIdSSLByteArray;
  3624. var
  3625. pSession: PSSL_SESSION;
  3626. begin
  3627. Result.Length := 0;
  3628. Result.Data := nil;
  3629. if Assigned(SSL_get_session) and Assigned(SSL_SESSION_get_id) then
  3630. begin
  3631. if fSSL <> nil then begin
  3632. pSession := SSL_get_session(fSSL);
  3633. if pSession <> nil then begin
  3634. Result.Data := PByte(SSL_SESSION_get_id(pSession, @Result.Length));
  3635. end;
  3636. end;
  3637. end;
  3638. end;
  3639. function TIdSSLSocket.GetSessionIDAsString:String;
  3640. var
  3641. Data: TIdSSLByteArray;
  3642. i: TIdC_UINT;
  3643. LDataPtr: PByte;
  3644. begin
  3645. Result := ''; {Do not Localize}
  3646. Data := GetSessionID;
  3647. if Data.Length > 0 then begin
  3648. for i := 0 to Data.Length-1 do begin
  3649. // RLebeau: not all Delphi versions support indexed access using PByte
  3650. LDataPtr := Data.Data;
  3651. Inc(LDataPtr, I);
  3652. Result := Result + IndyFormat('%.2x', [LDataPtr^]);{do not localize}
  3653. end;
  3654. end;
  3655. end;
  3656. procedure TIdSSLSocket.SetCipherList(CipherList: String);
  3657. //var
  3658. // tmpPStr: PAnsiChar;
  3659. begin
  3660. {
  3661. fCipherList := CipherList;
  3662. fCipherList_Ch := True;
  3663. aCipherList := aCipherList+#0;
  3664. if hSSL <> nil then f_SSL_set_cipher_list(hSSL, @aCipherList[1]);
  3665. }
  3666. end;
  3667. ///////////////////////////////////////////////////////////////
  3668. // X509 Certificate
  3669. ///////////////////////////////////////////////////////////////
  3670. { TIdX509Name }
  3671. function TIdX509Name.CertInOneLine: String;
  3672. var
  3673. LOneLine: array[0..2048] of TIdAnsiChar;
  3674. begin
  3675. if FX509Name = nil then begin
  3676. Result := ''; {Do not Localize}
  3677. end else begin
  3678. Result := String(X509_NAME_oneline(FX509Name, @LOneLine[0], SizeOf(LOneLine)));
  3679. end;
  3680. end;
  3681. function TIdX509Name.GetHash: TIdSSLULong;
  3682. begin
  3683. if FX509Name = nil then begin
  3684. FillChar(Result, SizeOf(Result), 0)
  3685. end else begin
  3686. Result.C1 := X509_NAME_hash(FX509Name);
  3687. end;
  3688. end;
  3689. function TIdX509Name.GetHashAsString: String;
  3690. begin
  3691. Result := IndyFormat('%.8x', [Hash.L1]); {do not localize}
  3692. end;
  3693. constructor TIdX509Name.Create(aX509Name: PX509_NAME);
  3694. begin
  3695. Inherited Create;
  3696. FX509Name := aX509Name;
  3697. end;
  3698. ///////////////////////////////////////////////////////////////
  3699. // X509 Certificate
  3700. ///////////////////////////////////////////////////////////////
  3701. { TIdX509Info }
  3702. constructor TIdX509Info.Create(aX509: PX509);
  3703. begin
  3704. inherited Create;
  3705. FX509 := aX509;
  3706. end;
  3707. { TIdX509Fingerprints }
  3708. function TIdX509Fingerprints.GetMD5: TIdSSLEVP_MD;
  3709. begin
  3710. CheckMD5Permitted;
  3711. X509_digest(FX509, EVP_md5, PByte(@Result.MD), Result.Length);
  3712. end;
  3713. function TIdX509Fingerprints.GetMD5AsString: String;
  3714. begin
  3715. Result := MDAsString(MD5);
  3716. end;
  3717. function TIdX509Fingerprints.GetSHA1: TIdSSLEVP_MD;
  3718. begin
  3719. X509_digest(FX509, EVP_sha1, PByte(@Result.MD), Result.Length);
  3720. end;
  3721. function TIdX509Fingerprints.GetSHA1AsString: String;
  3722. begin
  3723. Result := MDAsString(SHA1);
  3724. end;
  3725. function TIdX509Fingerprints.GetSHA224 : TIdSSLEVP_MD;
  3726. begin
  3727. if Assigned(EVP_sha224) then begin
  3728. X509_digest(FX509, EVP_sha224, PByte(@Result.MD), Result.Length);
  3729. end else begin
  3730. FillChar(Result, SizeOf(Result), 0);
  3731. end;
  3732. end;
  3733. function TIdX509Fingerprints.GetSHA224AsString : String;
  3734. begin
  3735. if Assigned(EVP_sha224) then begin
  3736. Result := MDAsString(SHA224);
  3737. end else begin
  3738. Result := '';
  3739. end;
  3740. end;
  3741. function TIdX509Fingerprints.GetSHA256 : TIdSSLEVP_MD;
  3742. begin
  3743. if Assigned(EVP_sha256) then begin
  3744. X509_digest(FX509, EVP_sha256, PByte(@Result.MD), Result.Length);
  3745. end else begin
  3746. FillChar(Result, SizeOf(Result), 0);
  3747. end;
  3748. end;
  3749. function TIdX509Fingerprints.GetSHA256AsString : String;
  3750. begin
  3751. if Assigned(EVP_sha256) then begin
  3752. Result := MDAsString(SHA256);
  3753. end else begin
  3754. Result := '';
  3755. end;
  3756. end;
  3757. function TIdX509Fingerprints.GetSHA384 : TIdSSLEVP_MD;
  3758. begin
  3759. if Assigned(EVP_SHA384) then begin
  3760. X509_digest(FX509, EVP_SHA384, PByte(@Result.MD), Result.Length);
  3761. end else begin
  3762. FillChar(Result, SizeOf(Result), 0);
  3763. end;
  3764. end;
  3765. function TIdX509Fingerprints.GetSHA384AsString : String;
  3766. begin
  3767. if Assigned(EVP_SHA384) then begin
  3768. Result := MDAsString(SHA384);
  3769. end else begin
  3770. Result := '';
  3771. end;
  3772. end;
  3773. function TIdX509Fingerprints.GetSHA512 : TIdSSLEVP_MD;
  3774. begin
  3775. if Assigned(EVP_sha512) then begin
  3776. X509_digest(FX509, EVP_sha512, PByte(@Result.MD), Result.Length);
  3777. end else begin
  3778. FillChar(Result, SizeOf(Result), 0);
  3779. end;
  3780. end;
  3781. function TIdX509Fingerprints.GetSHA512AsString : String;
  3782. begin
  3783. if Assigned(EVP_sha512) then begin
  3784. Result := MDAsString(SHA512);
  3785. end else begin
  3786. Result := '';
  3787. end;
  3788. end;
  3789. { TIdX509SigInfo }
  3790. function TIdX509SigInfo.GetSignature: String;
  3791. begin
  3792. Result := BytesToHexString(FX509^.signature^.data, FX509^.signature^.length);
  3793. end;
  3794. function TIdX509SigInfo.GetSigType: TIdC_INT;
  3795. begin
  3796. Result := X509_get_signature_type(FX509);
  3797. end;
  3798. function TIdX509SigInfo.GetSigTypeAsString: String;
  3799. begin
  3800. Result := String(OBJ_nid2ln(SigType));
  3801. end;
  3802. { TIdX509 }
  3803. constructor TIdX509.Create(aX509: PX509; aCanFreeX509: Boolean = True);
  3804. begin
  3805. inherited Create;
  3806. //don't create FDisplayInfo unless specifically requested.
  3807. FDisplayInfo := nil;
  3808. FX509 := aX509;
  3809. FCanFreeX509 := aCanFreeX509;
  3810. FFingerprints := TIdX509Fingerprints.Create(FX509);
  3811. FSigInfo := TIdX509SigInfo.Create(FX509);
  3812. FSubject := nil;
  3813. FIssuer := nil;
  3814. end;
  3815. destructor TIdX509.Destroy;
  3816. begin
  3817. FreeAndNil(FDisplayInfo);
  3818. FreeAndNil(FSubject);
  3819. FreeAndNil(FIssuer);
  3820. FreeAndNil(FFingerprints);
  3821. FreeAndNil(FSigInfo);
  3822. { If the X.509 certificate handle was obtained from a certificate
  3823. store or from the SSL connection as a peer certificate, then DO NOT
  3824. free it here! The memory is owned by the OpenSSL library and will
  3825. crash the library if Indy tries to free its private memory here }
  3826. if FCanFreeX509 then begin
  3827. X509_free(FX509);
  3828. end;
  3829. inherited Destroy;
  3830. end;
  3831. function TIdX509.GetDisplayInfo: TStrings;
  3832. begin
  3833. if not Assigned(FDisplayInfo) then begin
  3834. FDisplayInfo := TStringList.Create;
  3835. DumpCert(FDisplayInfo, FX509);
  3836. end;
  3837. Result := FDisplayInfo;
  3838. end;
  3839. function TIdX509.GetSerialNumber: String;
  3840. var
  3841. LSN : PASN1_INTEGER;
  3842. begin
  3843. if FX509 <> nil then begin
  3844. LSN := X509_get_serialNumber(FX509);
  3845. Result := BytesToHexString(LSN.data, LSN.length);
  3846. end else begin
  3847. Result := '';
  3848. end;
  3849. end;
  3850. function TIdX509.GetVersion : TIdC_LONG;
  3851. begin
  3852. Result := X509_get_version(FX509);
  3853. end;
  3854. function TIdX509.RSubject: TIdX509Name;
  3855. var
  3856. Lx509_name: PX509_NAME;
  3857. Begin
  3858. if not Assigned(FSubject) then begin
  3859. if FX509 <> nil then begin
  3860. Lx509_name := X509_get_subject_name(FX509);
  3861. end else begin
  3862. Lx509_name := nil;
  3863. end;
  3864. FSubject := TIdX509Name.Create(Lx509_name);
  3865. end;
  3866. Result := FSubject;
  3867. end;
  3868. function TIdX509.RIssuer: TIdX509Name;
  3869. var
  3870. Lx509_name: PX509_NAME;
  3871. begin
  3872. if not Assigned(FIssuer) then begin
  3873. if FX509 <> nil then begin
  3874. Lx509_name := X509_get_issuer_name(FX509);
  3875. end else begin
  3876. Lx509_name := nil;
  3877. end;
  3878. FIssuer := TIdX509Name.Create(Lx509_name);
  3879. End;
  3880. Result := FIssuer;
  3881. end;
  3882. function TIdX509.RFingerprint: TIdSSLEVP_MD;
  3883. begin
  3884. X509_digest(FX509, EVP_md5, PByte(@Result.MD), Result.Length);
  3885. end;
  3886. function TIdX509.RFingerprintAsString: String;
  3887. begin
  3888. Result := MDAsString(Fingerprint);
  3889. end;
  3890. function TIdX509.RnotBefore: TDateTime;
  3891. begin
  3892. if FX509 = nil then begin
  3893. Result := 0
  3894. end else begin
  3895. //This is a safe typecast since PASN1_UTCTIME and PASN1_TIME are really
  3896. //pointers to ASN1 strings since ASN1_UTCTIME amd ASM1_TIME are ASN1_STRING.
  3897. Result := UTCTime2DateTime(PASN1_UTCTIME(X509_get_notBefore(FX509)));
  3898. end;
  3899. end;
  3900. function TIdX509.RnotAfter:TDateTime;
  3901. begin
  3902. if FX509 = nil then begin
  3903. Result := 0
  3904. end else begin
  3905. Result := UTCTime2DateTime(PASN1_UTCTIME(X509_get_notAfter(FX509)));
  3906. end;
  3907. end;
  3908. ///////////////////////////////////////////////////////////////
  3909. // TIdSSLCipher
  3910. ///////////////////////////////////////////////////////////////
  3911. constructor TIdSSLCipher.Create(AOwner: TIdSSLSocket);
  3912. begin
  3913. inherited Create;
  3914. FSSLSocket := AOwner;
  3915. end;
  3916. destructor TIdSSLCipher.Destroy;
  3917. begin
  3918. inherited Destroy;
  3919. end;
  3920. function TIdSSLCipher.GetDescription;
  3921. var
  3922. Buf: array[0..1024] of TIdAnsiChar;
  3923. begin
  3924. Result := String(SSL_CIPHER_description(SSL_get_current_cipher(FSSLSocket.fSSL), @Buf[0], SizeOf(Buf)-1));
  3925. end;
  3926. function TIdSSLCipher.GetName:String;
  3927. begin
  3928. Result := String(SSL_CIPHER_get_name(SSL_get_current_cipher(FSSLSocket.fSSL)));
  3929. end;
  3930. function TIdSSLCipher.GetBits:TIdC_INT;
  3931. begin
  3932. SSL_CIPHER_get_bits(SSL_get_current_cipher(FSSLSocket.fSSL), Result);
  3933. end;
  3934. function TIdSSLCipher.GetVersion:String;
  3935. begin
  3936. Result := String(SSL_CIPHER_get_version(SSL_get_current_cipher(FSSLSocket.fSSL)));
  3937. end;
  3938. {$I IdSymbolDeprecatedOff.inc}
  3939. initialization
  3940. Assert(SSLIsLoaded=nil);
  3941. SSLIsLoaded := TIdThreadSafeBoolean.Create;
  3942. {$I IdSymbolDeprecatedOff.inc}
  3943. RegisterSSL('OpenSSL','Indy Pit Crew', {do not localize}
  3944. 'Copyright '+Char(169)+' 1993 - 2023'#10#13 + {do not localize}
  3945. 'Chad Z. Hower (Kudzu) and the Indy Pit Crew. All rights reserved.', {do not localize}
  3946. 'Open SSL Support DLL Delphi and C++Builder interface', {do not localize}
  3947. 'http://www.indyproject.org/'#10#13 + {do not localize}
  3948. 'Original Author - Gregor Ibic', {do not localize}
  3949. TIdSSLIOHandlerSocketOpenSSL,
  3950. TIdServerIOHandlerSSLOpenSSL);
  3951. {$I IdSymbolDeprecatedOn.inc}
  3952. TIdSSLIOHandlerSocketOpenSSL.RegisterIOHandler;
  3953. finalization
  3954. // TODO: TIdSSLIOHandlerSocketOpenSSL.UnregisterIOHandler;
  3955. UnLoadOpenSSLLibrary;
  3956. //free the lock last as unload makes calls that use it
  3957. FreeAndNil(SSLIsLoaded);
  3958. end.