IdSSLOpenSSL.pas 128 KB

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