IdSSLOpenSSL.pas 140 KB

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