IdSSLOpenSSL.pas 130 KB

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