IdSSLOpenSSL.pas 127 KB

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