digestmd5.c 130 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778
  1. /* DIGEST-MD5 SASL plugin
  2. * Ken Murchison
  3. * Rob Siemborski
  4. * Tim Martin
  5. * Alexey Melnikov
  6. */
  7. /*
  8. * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
  9. *
  10. * Redistribution and use in source and binary forms, with or without
  11. * modification, are permitted provided that the following conditions
  12. * are met:
  13. *
  14. * 1. Redistributions of source code must retain the above copyright
  15. * notice, this list of conditions and the following disclaimer.
  16. *
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in
  19. * the documentation and/or other materials provided with the
  20. * distribution.
  21. *
  22. * 3. The name "Carnegie Mellon University" must not be used to
  23. * endorse or promote products derived from this software without
  24. * prior written permission. For permission or any other legal
  25. * details, please contact
  26. * Carnegie Mellon University
  27. * Center for Technology Transfer and Enterprise Creation
  28. * 4615 Forbes Avenue
  29. * Suite 302
  30. * Pittsburgh, PA 15213
  31. * (412) 268-7393, fax: (412) 268-7395
  32. * innovation@andrew.cmu.edu
  33. *
  34. * 4. Redistributions of any form whatsoever must retain the following
  35. * acknowledgment:
  36. * "This product includes software developed by Computing Services
  37. * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
  38. *
  39. * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  40. * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  41. * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  42. * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  43. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  44. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  45. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  46. */
  47. #include <config.h>
  48. #include <stdlib.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51. #ifndef macintosh
  52. #include <sys/types.h>
  53. #include <sys/stat.h>
  54. #endif
  55. #include <fcntl.h>
  56. #include <ctype.h>
  57. /* DES support */
  58. #ifdef WITH_DES
  59. # ifdef WITH_SSL_DES
  60. # include <openssl/des.h>
  61. # include <openssl/opensslv.h>
  62. # if (OPENSSL_VERSION_NUMBER >= 0x0090700f) && \
  63. !defined(OPENSSL_ENABLE_OLD_DES_SUPPORT)
  64. # define des_cblock DES_cblock
  65. # define des_key_schedule DES_key_schedule
  66. # define des_key_sched(k,ks) \
  67. DES_key_sched((k),&(ks))
  68. # define des_cbc_encrypt(i,o,l,k,iv,e) \
  69. DES_cbc_encrypt((i),(o),(l),&(k),(iv),(e))
  70. # define des_ede2_cbc_encrypt(i,o,l,k1,k2,iv,e) \
  71. DES_ede2_cbc_encrypt((i),(o),(l),&(k1),&(k2),(iv),(e))
  72. # endif /* OpenSSL 0.9.7+ w/o old DES support */
  73. # else /* system DES library */
  74. #ifdef HAVE_DES_H
  75. # error #include <des.h>
  76. #endif
  77. # endif
  78. #endif /* WITH_DES */
  79. #ifdef WIN32
  80. # include <winsock2.h>
  81. #else /* Unix */
  82. # include <netinet/in.h>
  83. #endif /* WIN32 */
  84. #include <sasl.h>
  85. #include <saslplug.h>
  86. #include "plugin_common.h"
  87. #ifndef WIN32
  88. extern int strcasecmp(const char *s1, const char *s2);
  89. #endif /* end WIN32 */
  90. #ifdef macintosh
  91. #error #include <sasl_md5_plugin_decl.h>
  92. #endif
  93. /* external definitions */
  94. #define bool int
  95. #ifndef TRUE
  96. #define TRUE (1)
  97. #define FALSE (0)
  98. #endif
  99. /* MAX_UIN32_DIV_10 * 10 + MAX_UIN32_MOD_10 == 2^32-1 == 4294967295 */
  100. #define MAX_UIN32_DIV_10 429496729
  101. #define MAX_UIN32_MOD_10 5
  102. #define DEFAULT_BUFSIZE 0xFFFF
  103. #define MAX_SASL_BUFSIZE 0xFFFFFF
  104. /***************************** Common Section *****************************/
  105. /* Definitions */
  106. #define NONCE_SIZE (32) /* arbitrary */
  107. /* Layer Flags */
  108. #define DIGEST_NOLAYER (1)
  109. #define DIGEST_INTEGRITY (2)
  110. #define DIGEST_PRIVACY (4)
  111. /* defines */
  112. #define HASHLEN 16
  113. typedef unsigned char HASH[HASHLEN + 1];
  114. #define HASHHEXLEN 32
  115. typedef unsigned char HASHHEX[HASHHEXLEN + 1];
  116. #define MAC_SIZE 10
  117. #define MAC_OFFS 2
  118. const char *SEALING_CLIENT_SERVER="Digest H(A1) to client-to-server sealing key magic constant";
  119. const char *SEALING_SERVER_CLIENT="Digest H(A1) to server-to-client sealing key magic constant";
  120. const char *SIGNING_CLIENT_SERVER="Digest session key to client-to-server signing key magic constant";
  121. const char *SIGNING_SERVER_CLIENT="Digest session key to server-to-client signing key magic constant";
  122. #define HT (9)
  123. #define CR (13)
  124. #define LF (10)
  125. #define SP (32)
  126. #define DEL (127)
  127. #define NEED_ESCAPING "\"\\"
  128. #define REALM_CHAL_PREFIX "Available realms:"
  129. static char *quote (char *str);
  130. struct context;
  131. /* function definitions for cipher encode/decode */
  132. typedef int cipher_function_t(struct context *,
  133. const char *,
  134. unsigned,
  135. unsigned char[],
  136. char *,
  137. unsigned *);
  138. typedef int cipher_init_t(struct context *, unsigned char [16],
  139. unsigned char [16]);
  140. typedef void cipher_free_t(struct context *);
  141. enum Context_type { SERVER = 0, CLIENT = 1 };
  142. typedef struct cipher_context cipher_context_t;
  143. /* cached auth info used for fast reauth */
  144. typedef struct reauth_entry {
  145. char *authid;
  146. char *realm;
  147. unsigned char *nonce;
  148. unsigned int nonce_count;
  149. unsigned char *cnonce;
  150. union {
  151. struct {
  152. time_t timestamp;
  153. } s; /* server stuff */
  154. struct {
  155. char *serverFQDN;
  156. int protection;
  157. struct digest_cipher *cipher;
  158. unsigned long server_maxbuf;
  159. /* for HTTP mode (RFC 2617) only */
  160. char *algorithm;
  161. unsigned char *opaque;
  162. } c; /* client stuff */
  163. } u;
  164. } reauth_entry_t;
  165. typedef struct reauth_cache {
  166. /* static stuff */
  167. enum Context_type i_am; /* are we the client or server? */
  168. time_t timeout;
  169. void *mutex;
  170. unsigned size;
  171. reauth_entry_t *e; /* fixed-size hash table of entries */
  172. } reauth_cache_t;
  173. /* global context for reauth use */
  174. typedef struct digest_glob_context {
  175. reauth_cache_t *reauth;
  176. } digest_glob_context_t;
  177. /* context that stores info */
  178. typedef struct context {
  179. int state; /* state in the authentication we are in */
  180. enum Context_type i_am; /* are we the client or server? */
  181. int http_mode; /* use RFC 2617 compatible protocol? */
  182. reauth_cache_t *reauth;
  183. char *authid;
  184. char *realm;
  185. unsigned char *nonce;
  186. unsigned int nonce_count;
  187. unsigned char *cnonce;
  188. /* only used by the client */
  189. char ** realms;
  190. int realm_cnt;
  191. char *response_value;
  192. unsigned int seqnum;
  193. unsigned int rec_seqnum; /* for checking integrity */
  194. HASH Ki_send;
  195. HASH Ki_receive;
  196. HASH HA1; /* Kcc or Kcs */
  197. /* copy of utils from the params structures */
  198. const sasl_utils_t *utils;
  199. /* For general use */
  200. char *out_buf;
  201. unsigned out_buf_len;
  202. /* for encoding/decoding */
  203. buffer_info_t *enc_in_buf;
  204. char *encode_buf, *decode_buf, *decode_packet_buf;
  205. unsigned encode_buf_len, decode_buf_len, decode_packet_buf_len;
  206. decode_context_t decode_context;
  207. /* if privacy mode is used use these functions for encode and decode */
  208. cipher_function_t *cipher_enc;
  209. cipher_function_t *cipher_dec;
  210. cipher_init_t *cipher_init;
  211. cipher_free_t *cipher_free;
  212. struct cipher_context *cipher_enc_context;
  213. struct cipher_context *cipher_dec_context;
  214. } context_t;
  215. struct digest_cipher {
  216. char *name;
  217. sasl_ssf_t ssf;
  218. int n; /* bits to make privacy key */
  219. int flag; /* a bitmask to make things easier for us */
  220. cipher_function_t *cipher_enc;
  221. cipher_function_t *cipher_dec;
  222. cipher_init_t *cipher_init;
  223. cipher_free_t *cipher_free;
  224. };
  225. #if 0
  226. static const unsigned char *COLON = ":";
  227. #else
  228. static const unsigned char COLON[] = { ':', '\0' };
  229. #endif
  230. /* Hashes a string to produce an unsigned short */
  231. static unsigned hash(const char *str)
  232. {
  233. unsigned val = 0;
  234. int i;
  235. while (str && *str) {
  236. i = (int) *str;
  237. val ^= i;
  238. val <<= 1;
  239. str++;
  240. }
  241. return val;
  242. }
  243. static void CvtHex(HASH Bin, HASHHEX Hex)
  244. {
  245. unsigned short i;
  246. unsigned char j;
  247. for (i = 0; i < HASHLEN; i++) {
  248. j = (Bin[i] >> 4) & 0xf;
  249. if (j <= 9)
  250. Hex[i * 2] = (j + '0');
  251. else
  252. Hex[i * 2] = (j + 'a' - 10);
  253. j = Bin[i] & 0xf;
  254. if (j <= 9)
  255. Hex[i * 2 + 1] = (j + '0');
  256. else
  257. Hex[i * 2 + 1] = (j + 'a' - 10);
  258. }
  259. Hex[HASHHEXLEN] = '\0';
  260. }
  261. /*
  262. * calculate request-digest/response-digest as per HTTP Digest spec
  263. */
  264. void
  265. DigestCalcResponse(const sasl_utils_t * utils,
  266. HASHHEX HA1, /* HEX(H(A1)) */
  267. unsigned char *pszNonce, /* nonce from server */
  268. unsigned int pszNonceCount, /* 8 hex digits */
  269. unsigned char *pszCNonce, /* client nonce */
  270. unsigned char *pszQop, /* qop-value: "", "auth",
  271. * "auth-int" */
  272. unsigned char *pszDigestUri, /* requested URL */
  273. unsigned char *pszMethod,
  274. HASHHEX HEntity, /* H(entity body) if qop="auth-int" */
  275. HASHHEX Response /* request-digest or response-digest */
  276. )
  277. {
  278. MD5_CTX Md5Ctx;
  279. HASH HA2;
  280. HASH RespHash;
  281. HASHHEX HA2Hex;
  282. unsigned char ncvalue[10];
  283. /* calculate H(A2) */
  284. utils->MD5Init(&Md5Ctx);
  285. if (pszMethod != NULL) {
  286. utils->MD5Update(&Md5Ctx, pszMethod, (unsigned) strlen((char *) pszMethod));
  287. }
  288. utils->MD5Update(&Md5Ctx, (unsigned char *) COLON, 1);
  289. /* utils->MD5Update(&Md5Ctx, (unsigned char *) "AUTHENTICATE:", 13); */
  290. utils->MD5Update(&Md5Ctx, pszDigestUri, (unsigned) strlen((char *) pszDigestUri));
  291. if (strcasecmp((char *) pszQop, "auth") != 0) {
  292. /* append ":00000000000000000000000000000000" */
  293. utils->MD5Update(&Md5Ctx, COLON, 1);
  294. utils->MD5Update(&Md5Ctx, HEntity, HASHHEXLEN);
  295. }
  296. utils->MD5Final(HA2, &Md5Ctx);
  297. CvtHex(HA2, HA2Hex);
  298. /* calculate response */
  299. utils->MD5Init(&Md5Ctx);
  300. utils->MD5Update(&Md5Ctx, HA1, HASHHEXLEN);
  301. utils->MD5Update(&Md5Ctx, COLON, 1);
  302. utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
  303. utils->MD5Update(&Md5Ctx, COLON, 1);
  304. if (*pszQop) {
  305. sprintf((char *)ncvalue, "%08x", pszNonceCount);
  306. utils->MD5Update(&Md5Ctx, ncvalue, (unsigned) strlen((char *)ncvalue));
  307. utils->MD5Update(&Md5Ctx, COLON, 1);
  308. utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
  309. utils->MD5Update(&Md5Ctx, COLON, 1);
  310. utils->MD5Update(&Md5Ctx, pszQop, (unsigned) strlen((char *) pszQop));
  311. utils->MD5Update(&Md5Ctx, COLON, 1);
  312. }
  313. utils->MD5Update(&Md5Ctx, HA2Hex, HASHHEXLEN);
  314. utils->MD5Final(RespHash, &Md5Ctx);
  315. CvtHex(RespHash, Response);
  316. }
  317. static bool UTF8_In_8859_1(const unsigned char *base, size_t len)
  318. {
  319. const unsigned char *scan, *end;
  320. end = base + len;
  321. for (scan = base; scan < end; ++scan) {
  322. if (*scan > 0xC3)
  323. break; /* abort if outside 8859-1 */
  324. if (*scan >= 0xC0 && *scan <= 0xC3) {
  325. if (++scan == end || *scan < 0x80 || *scan > 0xBF)
  326. break;
  327. }
  328. }
  329. /* if scan >= end, then this is a 8859-1 string. */
  330. return (scan >= end);
  331. }
  332. /*
  333. * if the string is entirely in the 8859-1 subset of UTF-8, then translate to
  334. * 8859-1 prior to MD5
  335. */
  336. static void MD5_UTF8_8859_1(const sasl_utils_t * utils,
  337. MD5_CTX * ctx,
  338. bool In_ISO_8859_1,
  339. const unsigned char *base,
  340. int len)
  341. {
  342. const unsigned char *scan, *end;
  343. unsigned char cbuf;
  344. end = base + len;
  345. /* if we found a character outside 8859-1, don't alter string */
  346. if (!In_ISO_8859_1) {
  347. utils->MD5Update(ctx, base, len);
  348. return;
  349. }
  350. /* convert to 8859-1 prior to applying hash */
  351. do {
  352. for (scan = base; scan < end && *scan < 0xC0; ++scan);
  353. if (scan != base)
  354. utils->MD5Update(ctx, base, (unsigned) (scan - base));
  355. if (scan + 1 >= end)
  356. break;
  357. cbuf = ((scan[0] & 0x3) << 6) | (scan[1] & 0x3f);
  358. utils->MD5Update(ctx, &cbuf, 1);
  359. base = scan + 2;
  360. }
  361. while (base < end);
  362. }
  363. /**
  364. * Returns true if it mangled the username.
  365. */
  366. static bool DigestCalcSecret(const sasl_utils_t * utils,
  367. unsigned char *pszUserName,
  368. unsigned char *pszRealm,
  369. unsigned char *Password,
  370. int PasswordLen,
  371. bool Ignore_8859,
  372. HASH HA1)
  373. {
  374. bool In_8859_1;
  375. bool Any_8859_1 = FALSE;
  376. MD5_CTX Md5Ctx;
  377. /* Chris Newman clarified that the following text in DIGEST-MD5 spec
  378. is bogus: "if name and password are both in ISO 8859-1 charset"
  379. We shoud use code example instead */
  380. utils->MD5Init(&Md5Ctx);
  381. /* We have to convert UTF-8 to ISO-8859-1 if possible */
  382. if (Ignore_8859 == FALSE) {
  383. In_8859_1 = UTF8_In_8859_1(pszUserName, strlen((char *) pszUserName));
  384. MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
  385. pszUserName, (unsigned) strlen((char *) pszUserName));
  386. Any_8859_1 |= In_8859_1;
  387. } else {
  388. utils->MD5Update(&Md5Ctx, pszUserName, (unsigned) strlen((char *) pszUserName));
  389. }
  390. utils->MD5Update(&Md5Ctx, COLON, 1);
  391. /* a NULL realm is equivalent to the empty string */
  392. if (pszRealm != NULL && pszRealm[0] != '\0') {
  393. if (Ignore_8859 == FALSE) {
  394. /* We have to convert UTF-8 to ISO-8859-1 if possible */
  395. In_8859_1 = UTF8_In_8859_1(pszRealm, strlen((char *) pszRealm));
  396. MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
  397. pszRealm, (unsigned) strlen((char *) pszRealm));
  398. Any_8859_1 |= In_8859_1;
  399. } else {
  400. utils->MD5Update(&Md5Ctx, pszRealm, (unsigned) strlen((char *) pszRealm));
  401. }
  402. }
  403. utils->MD5Update(&Md5Ctx, COLON, 1);
  404. if (Ignore_8859 == FALSE) {
  405. /* We have to convert UTF-8 to ISO-8859-1 if possible */
  406. In_8859_1 = UTF8_In_8859_1(Password, PasswordLen);
  407. MD5_UTF8_8859_1(utils, &Md5Ctx, In_8859_1,
  408. Password, PasswordLen);
  409. Any_8859_1 |= In_8859_1;
  410. } else {
  411. utils->MD5Update(&Md5Ctx, Password, PasswordLen);
  412. }
  413. utils->MD5Final(HA1, &Md5Ctx);
  414. return Any_8859_1;
  415. }
  416. static unsigned char *create_nonce(const sasl_utils_t * utils)
  417. {
  418. unsigned char *base64buf;
  419. int base64len;
  420. char *ret = (char *) utils->malloc(NONCE_SIZE);
  421. if (ret == NULL)
  422. return NULL;
  423. utils->rand(utils->rpool, (char *) ret, NONCE_SIZE);
  424. /* base 64 encode it so it has valid chars */
  425. base64len = (NONCE_SIZE * 4 / 3) + (NONCE_SIZE % 3 ? 4 : 0);
  426. base64buf = (unsigned char *) utils->malloc(base64len + 1);
  427. if (base64buf == NULL) {
  428. utils->seterror(utils->conn, 0, "Unable to allocate final buffer");
  429. return NULL;
  430. }
  431. /*
  432. * Returns SASL_OK on success, SASL_BUFOVER if result won't fit
  433. */
  434. if (utils->encode64(ret, NONCE_SIZE,
  435. (char *) base64buf, base64len, NULL) != SASL_OK) {
  436. utils->free(ret);
  437. return NULL;
  438. }
  439. utils->free(ret);
  440. return base64buf;
  441. }
  442. static int add_to_challenge(const sasl_utils_t *utils,
  443. char **str, unsigned *buflen, unsigned *curlen,
  444. char *name,
  445. unsigned char *value,
  446. bool need_quotes)
  447. {
  448. size_t namesize = strlen(name);
  449. size_t valuesize = strlen((char *) value);
  450. unsigned newlen;
  451. int ret;
  452. newlen = (unsigned) (*curlen + 1 + namesize + 2 + valuesize + 2);
  453. ret = _plug_buf_alloc(utils, str, buflen, newlen);
  454. if(ret != SASL_OK) return ret;
  455. if (*curlen > 0) {
  456. strcat(*str, ",");
  457. strcat(*str, name);
  458. } else {
  459. strcpy(*str, name);
  460. }
  461. if (need_quotes) {
  462. strcat(*str, "=\"");
  463. /* Check if the value needs quoting */
  464. if (strpbrk ((char *)value, NEED_ESCAPING) != NULL) {
  465. char * quoted = quote ((char *) value);
  466. if (quoted == NULL)
  467. MEMERROR(utils);
  468. valuesize = strlen(quoted);
  469. /* As the quoted string is bigger, make sure we have enough
  470. space now */
  471. ret = _plug_buf_alloc(utils, str, buflen, newlen);
  472. if (ret == SASL_OK) {
  473. strcat(*str, quoted);
  474. free (quoted);
  475. } else {
  476. free (quoted);
  477. return ret;
  478. }
  479. } else {
  480. strcat(*str, (char *) value);
  481. }
  482. strcat(*str, "\"");
  483. } else {
  484. strcat(*str, "=");
  485. strcat(*str, (char *) value);
  486. }
  487. *curlen = newlen;
  488. return SASL_OK;
  489. }
  490. static int is_lws_char (char c)
  491. {
  492. return (c == ' ' || c == HT || c == CR || c == LF);
  493. }
  494. static char *skip_lws (char *s)
  495. {
  496. if (!s) return NULL;
  497. /* skipping spaces: */
  498. while (is_lws_char(s[0])) {
  499. if (s[0] == '\0') break;
  500. s++;
  501. }
  502. return s;
  503. }
  504. /* Same as skip_lws, but do this right to left */
  505. /* skip LWSP at the end of the value (if any), skip_r_lws returns pointer to
  506. the first LWSP character, NUL (if there were none) or NULL if the value
  507. is entirely from LWSP characters */
  508. static char *skip_r_lws (char *s)
  509. {
  510. char *end;
  511. size_t len;
  512. if (!s) return NULL;
  513. len = strlen(s);
  514. if (len == 0) return NULL;
  515. /* the last character before terminating NUL */
  516. end = s + len - 1;
  517. /* skipping spaces: */
  518. while (end > s && (end[0] == ' ' || end[0] == HT || end[0] == CR || end[0] == LF)) {
  519. end--;
  520. }
  521. /* If all string from spaces, return NULL */
  522. if (end == s && (end[0] == ' ' || end[0] == HT || end[0] == CR || end[0] == LF)) {
  523. return NULL;
  524. } else {
  525. return (end + 1);
  526. }
  527. }
  528. static char *skip_token (char *s, int caseinsensitive)
  529. {
  530. if(!s) return NULL;
  531. while (s[0]>SP) {
  532. if (s[0]==DEL || s[0]=='(' || s[0]==')' || s[0]=='<' || s[0]=='>' ||
  533. s[0]=='@' || s[0]==',' || s[0]==';' || s[0]==':' || s[0]=='\\' ||
  534. s[0]=='\'' || s[0]=='/' || s[0]=='[' || s[0]==']' || s[0]== '?' ||
  535. s[0]=='=' || s[0]== '{' || s[0]== '}') {
  536. if (caseinsensitive == 1) {
  537. if (!isupper((unsigned char) s[0]))
  538. break;
  539. } else {
  540. break;
  541. }
  542. }
  543. s++;
  544. }
  545. return s;
  546. }
  547. /* Convert a string to 32 bit unsigned integer.
  548. Any number of trailing spaces is allowed, but not a string
  549. entirely comprised of spaces */
  550. static bool str2ul32 (char *str, unsigned long * value)
  551. {
  552. unsigned int n;
  553. char c;
  554. if (str == NULL) {
  555. return (FALSE);
  556. }
  557. *value = 0;
  558. str = skip_lws (str);
  559. if (str[0] == '\0') {
  560. return (FALSE);
  561. }
  562. n = 0;
  563. while (str[0] != '\0') {
  564. c = str[0];
  565. if (!isdigit((int)c)) {
  566. return (FALSE);
  567. }
  568. /* Will overflow after adding additional digit */
  569. if (n > MAX_UIN32_DIV_10) {
  570. return (FALSE);
  571. } else if (n == MAX_UIN32_DIV_10 && ((unsigned) (c - '0') > MAX_UIN32_MOD_10)) {
  572. return (FALSE);
  573. }
  574. n = n * 10 + (unsigned) (c - '0');
  575. str++;
  576. }
  577. *value = n;
  578. return (TRUE);
  579. }
  580. /* NULL - error (unbalanced quotes),
  581. otherwise pointer to the first character after the value.
  582. The function performs work in place. */
  583. static char *unquote (char *qstr)
  584. {
  585. char *endvalue;
  586. int escaped = 0;
  587. char *outptr;
  588. if(!qstr) return NULL;
  589. if (qstr[0] == '"') {
  590. qstr++;
  591. outptr = qstr;
  592. for (endvalue = qstr; endvalue[0] != '\0'; endvalue++, outptr++) {
  593. if (escaped) {
  594. outptr[0] = endvalue[0];
  595. escaped = 0;
  596. }
  597. else if (endvalue[0] == '\\') {
  598. escaped = 1;
  599. outptr--; /* Will be incremented at the end of the loop */
  600. }
  601. else if (endvalue[0] == '"') {
  602. break;
  603. }
  604. else {
  605. outptr[0] = endvalue[0];
  606. }
  607. }
  608. if (endvalue[0] != '"') {
  609. return NULL;
  610. }
  611. while (outptr <= endvalue) {
  612. outptr[0] = '\0';
  613. outptr++;
  614. }
  615. endvalue++;
  616. }
  617. else { /* not qouted value (token) */
  618. /* qstr already contains output */
  619. endvalue = skip_token(qstr,0);
  620. };
  621. return endvalue;
  622. }
  623. /* Unlike unquote, this function returns an allocated quoted copy */
  624. static char *quote (char *str)
  625. {
  626. char *p;
  627. char *outp;
  628. char *result;
  629. int num_to_escape; /* How many characters need escaping */
  630. if (!str) return NULL;
  631. num_to_escape = 0;
  632. p = strpbrk (str, NEED_ESCAPING);
  633. while (p != NULL) {
  634. num_to_escape++;
  635. p = strpbrk (p + 1, NEED_ESCAPING);
  636. }
  637. if (num_to_escape == 0) {
  638. return (strdup (str));
  639. }
  640. result = malloc (strlen(str) + num_to_escape + 1);
  641. if (result == NULL) {
  642. return NULL;
  643. }
  644. for (p = str, outp = result; *p; p++) {
  645. if (*p == '"' || *p == '\\') {
  646. *outp = '\\';
  647. outp++;
  648. }
  649. *outp = *p;
  650. outp++;
  651. }
  652. *outp = '\0';
  653. return (result);
  654. }
  655. static void get_pair(char **in, char **name, char **value)
  656. {
  657. char *endpair;
  658. char *curp = *in;
  659. *name = NULL;
  660. *value = NULL;
  661. if (curp == NULL) return;
  662. while (curp[0] != '\0') {
  663. /* skipping spaces: */
  664. curp = skip_lws(curp);
  665. /* 'LWS "," LWS "," ...' is allowed by the DIGEST-MD5 ABNF */
  666. if (curp[0] == ',') {
  667. curp++;
  668. } else {
  669. break;
  670. }
  671. }
  672. if (curp[0] == '\0') {
  673. /* End of the string is not an error */
  674. *name = "";
  675. return;
  676. }
  677. *name = curp;
  678. curp = skip_token(curp,1);
  679. /* strip wierd chars */
  680. if (curp[0] != '=' && curp[0] != '\0') {
  681. *curp++ = '\0';
  682. };
  683. curp = skip_lws(curp);
  684. if (curp[0] != '=') { /* No '=' sign */
  685. *name = NULL;
  686. return;
  687. }
  688. curp[0] = '\0';
  689. curp++;
  690. curp = skip_lws(curp);
  691. *value = (curp[0] == '"') ? curp+1 : curp;
  692. endpair = unquote (curp);
  693. if (endpair == NULL) { /* Unbalanced quotes */
  694. *name = NULL;
  695. *value = NULL;
  696. return;
  697. }
  698. /* An optional LWS is allowed after the value. Skip it. */
  699. if (is_lws_char (endpair[0])) {
  700. /* Remove the trailing LWS from the value */
  701. *endpair++ = '\0';
  702. endpair = skip_lws(endpair);
  703. }
  704. /* syntax check: MUST be '\0' or ',' */
  705. if (endpair[0] == ',') {
  706. endpair[0] = '\0';
  707. endpair++; /* skipping <,> */
  708. } else if (endpair[0] != '\0') {
  709. *name = NULL;
  710. *value = NULL;
  711. return;
  712. }
  713. *in = endpair;
  714. }
  715. #ifdef WITH_DES
  716. struct des_context_s {
  717. des_key_schedule keysched; /* key schedule for des initialization */
  718. des_cblock ivec; /* initial vector for encoding */
  719. des_key_schedule keysched2; /* key schedule for 3des initialization */
  720. };
  721. typedef struct des_context_s des_context_t;
  722. /* slide the first 7 bytes of 'inbuf' into the high seven bits of the
  723. first 8 bytes of 'keybuf'. 'keybuf' better be 8 bytes long or longer. */
  724. static void slidebits(unsigned char *keybuf, unsigned char *inbuf)
  725. {
  726. keybuf[0] = inbuf[0];
  727. keybuf[1] = (inbuf[0]<<7) | (inbuf[1]>>1);
  728. keybuf[2] = (inbuf[1]<<6) | (inbuf[2]>>2);
  729. keybuf[3] = (inbuf[2]<<5) | (inbuf[3]>>3);
  730. keybuf[4] = (inbuf[3]<<4) | (inbuf[4]>>4);
  731. keybuf[5] = (inbuf[4]<<3) | (inbuf[5]>>5);
  732. keybuf[6] = (inbuf[5]<<2) | (inbuf[6]>>6);
  733. keybuf[7] = (inbuf[6]<<1);
  734. }
  735. /******************************
  736. *
  737. * 3DES functions
  738. *
  739. *****************************/
  740. static int dec_3des(context_t *text,
  741. const char *input,
  742. unsigned inputlen,
  743. unsigned char digest[16] __attribute__((unused)),
  744. char *output,
  745. unsigned *outputlen)
  746. {
  747. des_context_t *c = (des_context_t *) text->cipher_dec_context;
  748. int padding, p;
  749. des_ede2_cbc_encrypt((void *) input,
  750. (void *) output,
  751. inputlen,
  752. c->keysched,
  753. c->keysched2,
  754. &c->ivec,
  755. DES_DECRYPT);
  756. /* now chop off the padding */
  757. padding = output[inputlen - 11];
  758. if (padding < 1 || padding > 8) {
  759. /* invalid padding length */
  760. return SASL_FAIL;
  761. }
  762. /* verify all padding is correct */
  763. for (p = 1; p <= padding; p++) {
  764. if (output[inputlen - 10 - p] != padding) {
  765. return SASL_FAIL;
  766. }
  767. }
  768. /* chop off the padding */
  769. *outputlen = inputlen - padding - 10;
  770. return SASL_OK;
  771. }
  772. static int enc_3des(context_t *text,
  773. const char *input,
  774. unsigned inputlen,
  775. unsigned char digest[16],
  776. char *output,
  777. unsigned *outputlen)
  778. {
  779. des_context_t *c = (des_context_t *) text->cipher_enc_context;
  780. int len;
  781. int paddinglen;
  782. /* determine padding length */
  783. paddinglen = 8 - ((inputlen + 10) % 8);
  784. /* now construct the full stuff to be ciphered */
  785. memcpy(output, input, inputlen); /* text */
  786. memset(output+inputlen, paddinglen, paddinglen);/* pad */
  787. memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
  788. len=inputlen+paddinglen+10;
  789. des_ede2_cbc_encrypt((void *) output,
  790. (void *) output,
  791. len,
  792. c->keysched,
  793. c->keysched2,
  794. &c->ivec,
  795. DES_ENCRYPT);
  796. *outputlen=len;
  797. return SASL_OK;
  798. }
  799. static int init_3des(context_t *text,
  800. unsigned char enckey[16],
  801. unsigned char deckey[16])
  802. {
  803. des_context_t *c;
  804. unsigned char keybuf[8];
  805. /* allocate enc & dec context */
  806. c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
  807. if (c == NULL) return SASL_NOMEM;
  808. /* setup enc context */
  809. slidebits(keybuf, enckey);
  810. if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
  811. return SASL_FAIL;
  812. slidebits(keybuf, enckey + 7);
  813. if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
  814. return SASL_FAIL;
  815. memcpy(c->ivec, ((char *) enckey) + 8, 8);
  816. text->cipher_enc_context = (cipher_context_t *) c;
  817. /* setup dec context */
  818. c++;
  819. slidebits(keybuf, deckey);
  820. if (des_key_sched((des_cblock *) keybuf, c->keysched) < 0)
  821. return SASL_FAIL;
  822. slidebits(keybuf, deckey + 7);
  823. if (des_key_sched((des_cblock *) keybuf, c->keysched2) < 0)
  824. return SASL_FAIL;
  825. memcpy(c->ivec, ((char *) deckey) + 8, 8);
  826. text->cipher_dec_context = (cipher_context_t *) c;
  827. return SASL_OK;
  828. }
  829. /******************************
  830. *
  831. * DES functions
  832. *
  833. *****************************/
  834. static int dec_des(context_t *text,
  835. const char *input,
  836. unsigned inputlen,
  837. unsigned char digest[16] __attribute__((unused)),
  838. char *output,
  839. unsigned *outputlen)
  840. {
  841. des_context_t *c = (des_context_t *) text->cipher_dec_context;
  842. int p, padding = 0;
  843. des_cbc_encrypt((void *) input,
  844. (void *) output,
  845. inputlen,
  846. c->keysched,
  847. &c->ivec,
  848. DES_DECRYPT);
  849. /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
  850. this way) */
  851. memcpy(c->ivec, input + (inputlen - 8), 8);
  852. /* now chop off the padding */
  853. padding = output[inputlen - 11];
  854. if (padding < 1 || padding > 8) {
  855. /* invalid padding length */
  856. return SASL_FAIL;
  857. }
  858. /* verify all padding is correct */
  859. for (p = 1; p <= padding; p++) {
  860. if (output[inputlen - 10 - p] != padding) {
  861. return SASL_FAIL;
  862. }
  863. }
  864. /* chop off the padding */
  865. *outputlen = inputlen - padding - 10;
  866. return SASL_OK;
  867. }
  868. static int enc_des(context_t *text,
  869. const char *input,
  870. unsigned inputlen,
  871. unsigned char digest[16],
  872. char *output,
  873. unsigned *outputlen)
  874. {
  875. des_context_t *c = (des_context_t *) text->cipher_enc_context;
  876. int len;
  877. int paddinglen;
  878. /* determine padding length */
  879. paddinglen = 8 - ((inputlen+10) % 8);
  880. /* now construct the full stuff to be ciphered */
  881. memcpy(output, input, inputlen); /* text */
  882. memset(output+inputlen, paddinglen, paddinglen);/* pad */
  883. memcpy(output+inputlen+paddinglen, digest, 10); /* hmac */
  884. len = inputlen + paddinglen + 10;
  885. des_cbc_encrypt((void *) output,
  886. (void *) output,
  887. len,
  888. c->keysched,
  889. &c->ivec,
  890. DES_ENCRYPT);
  891. /* Update the ivec (des_cbc_encrypt implementations tend to be broken in
  892. this way) */
  893. memcpy(c->ivec, output + (len - 8), 8);
  894. *outputlen = len;
  895. return SASL_OK;
  896. }
  897. static int init_des(context_t *text,
  898. unsigned char enckey[16],
  899. unsigned char deckey[16])
  900. {
  901. des_context_t *c;
  902. unsigned char keybuf[8];
  903. /* allocate enc context */
  904. c = (des_context_t *) text->utils->malloc(2 * sizeof(des_context_t));
  905. if (c == NULL) return SASL_NOMEM;
  906. /* setup enc context */
  907. slidebits(keybuf, enckey);
  908. des_key_sched((des_cblock *) keybuf, c->keysched);
  909. memcpy(c->ivec, ((char *) enckey) + 8, 8);
  910. text->cipher_enc_context = (cipher_context_t *) c;
  911. /* setup dec context */
  912. c++;
  913. slidebits(keybuf, deckey);
  914. des_key_sched((des_cblock *) keybuf, c->keysched);
  915. memcpy(c->ivec, ((char *) deckey) + 8, 8);
  916. text->cipher_dec_context = (cipher_context_t *) c;
  917. return SASL_OK;
  918. }
  919. static void free_des(context_t *text)
  920. {
  921. /* free des contextss. only cipher_enc_context needs to be free'd,
  922. since cipher_dec_context was allocated at the same time. */
  923. if (text->cipher_enc_context) text->utils->free(text->cipher_enc_context);
  924. }
  925. #endif /* WITH_DES */
  926. #ifdef WITH_RC4
  927. #ifdef HAVE_OPENSSL
  928. #include <openssl/evp.h>
  929. static void free_rc4(context_t *text)
  930. {
  931. if (text->cipher_enc_context) {
  932. EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)text->cipher_enc_context);
  933. text->cipher_enc_context = NULL;
  934. }
  935. if (text->cipher_dec_context) {
  936. EVP_CIPHER_CTX_free((EVP_CIPHER_CTX *)text->cipher_dec_context);
  937. text->cipher_dec_context = NULL;
  938. }
  939. }
  940. static int init_rc4(context_t *text,
  941. unsigned char enckey[16],
  942. unsigned char deckey[16])
  943. {
  944. EVP_CIPHER_CTX *ctx;
  945. int rc;
  946. ctx = EVP_CIPHER_CTX_new();
  947. if (ctx == NULL) return SASL_NOMEM;
  948. rc = EVP_EncryptInit_ex(ctx, EVP_rc4(), NULL, enckey, NULL);
  949. if (rc != 1) return SASL_FAIL;
  950. text->cipher_enc_context = (void *)ctx;
  951. ctx = EVP_CIPHER_CTX_new();
  952. if (ctx == NULL) return SASL_NOMEM;
  953. rc = EVP_DecryptInit_ex(ctx, EVP_rc4(), NULL, deckey, NULL);
  954. if (rc != 1) return SASL_FAIL;
  955. text->cipher_dec_context = (void *)ctx;
  956. return SASL_OK;
  957. }
  958. static int dec_rc4(context_t *text,
  959. const char *input,
  960. unsigned inputlen,
  961. unsigned char digest[16] __attribute__((unused)),
  962. char *output,
  963. unsigned *outputlen)
  964. {
  965. int len;
  966. int rc;
  967. /* decrypt the text part & HMAC */
  968. rc = EVP_DecryptUpdate((EVP_CIPHER_CTX *)text->cipher_dec_context,
  969. (unsigned char *)output, &len,
  970. (const unsigned char *)input, inputlen);
  971. if (rc != 1) return SASL_FAIL;
  972. *outputlen = len;
  973. rc = EVP_DecryptFinal_ex((EVP_CIPHER_CTX *)text->cipher_dec_context,
  974. (unsigned char *)output + len, &len);
  975. if (rc != 1) return SASL_FAIL;
  976. *outputlen += len;
  977. /* subtract the HMAC to get the text length */
  978. *outputlen -= 10;
  979. return SASL_OK;
  980. }
  981. static int enc_rc4(context_t *text,
  982. const char *input,
  983. unsigned inputlen,
  984. unsigned char digest[16],
  985. char *output,
  986. unsigned *outputlen)
  987. {
  988. int len;
  989. int rc;
  990. /* encrypt the text part */
  991. rc = EVP_EncryptUpdate((EVP_CIPHER_CTX *)text->cipher_enc_context,
  992. (unsigned char *)output, &len,
  993. (const unsigned char *)input, inputlen);
  994. if (rc != 1) return SASL_FAIL;
  995. *outputlen = len;
  996. /* encrypt the `MAC part */
  997. rc = EVP_EncryptUpdate((EVP_CIPHER_CTX *)text->cipher_enc_context,
  998. (unsigned char *)output + *outputlen, &len,
  999. digest, 10);
  1000. if (rc != 1) return SASL_FAIL;
  1001. *outputlen += len;
  1002. rc = EVP_EncryptFinal_ex((EVP_CIPHER_CTX *)text->cipher_enc_context,
  1003. (unsigned char *)output + *outputlen, &len);
  1004. if (rc != 1) return SASL_FAIL;
  1005. *outputlen += len;
  1006. return SASL_OK;
  1007. }
  1008. #else
  1009. /* quick generic implementation of RC4 */
  1010. struct rc4_context_s {
  1011. unsigned char sbox[256];
  1012. int i, j;
  1013. };
  1014. typedef struct rc4_context_s rc4_context_t;
  1015. static void rc4_init(rc4_context_t *text,
  1016. const unsigned char *key,
  1017. unsigned keylen)
  1018. {
  1019. int i, j;
  1020. /* fill in linearly s0=0 s1=1... */
  1021. for (i=0;i<256;i++)
  1022. text->sbox[i]=i;
  1023. j=0;
  1024. for (i = 0; i < 256; i++) {
  1025. unsigned char tmp;
  1026. /* j = (j + Si + Ki) mod 256 */
  1027. j = (j + text->sbox[i] + key[i % keylen]) % 256;
  1028. /* swap Si and Sj */
  1029. tmp = text->sbox[i];
  1030. text->sbox[i] = text->sbox[j];
  1031. text->sbox[j] = tmp;
  1032. }
  1033. /* counters initialized to 0 */
  1034. text->i = 0;
  1035. text->j = 0;
  1036. }
  1037. static void rc4_encrypt(rc4_context_t *text,
  1038. const char *input,
  1039. char *output,
  1040. unsigned len)
  1041. {
  1042. int tmp;
  1043. int i = text->i;
  1044. int j = text->j;
  1045. int t;
  1046. int K;
  1047. const char *input_end = input + len;
  1048. while (input < input_end) {
  1049. i = (i + 1) % 256;
  1050. j = (j + text->sbox[i]) % 256;
  1051. /* swap Si and Sj */
  1052. tmp = text->sbox[i];
  1053. text->sbox[i] = text->sbox[j];
  1054. text->sbox[j] = tmp;
  1055. t = (text->sbox[i] + text->sbox[j]) % 256;
  1056. K = text->sbox[t];
  1057. /* byte K is Xor'ed with plaintext */
  1058. *output++ = *input++ ^ K;
  1059. }
  1060. text->i = i;
  1061. text->j = j;
  1062. }
  1063. static void rc4_decrypt(rc4_context_t *text,
  1064. const char *input,
  1065. char *output,
  1066. unsigned len)
  1067. {
  1068. int tmp;
  1069. int i = text->i;
  1070. int j = text->j;
  1071. int t;
  1072. int K;
  1073. const char *input_end = input + len;
  1074. while (input < input_end) {
  1075. i = (i + 1) % 256;
  1076. j = (j + text->sbox[i]) % 256;
  1077. /* swap Si and Sj */
  1078. tmp = text->sbox[i];
  1079. text->sbox[i] = text->sbox[j];
  1080. text->sbox[j] = tmp;
  1081. t = (text->sbox[i] + text->sbox[j]) % 256;
  1082. K = text->sbox[t];
  1083. /* byte K is Xor'ed with plaintext */
  1084. *output++ = *input++ ^ K;
  1085. }
  1086. text->i = i;
  1087. text->j = j;
  1088. }
  1089. static void free_rc4(context_t *text)
  1090. {
  1091. /* free rc4 context structures */
  1092. if (text->cipher_enc_context) {
  1093. text->utils->free(text->cipher_enc_context);
  1094. text->cipher_enc_context = NULL;
  1095. }
  1096. if (text->cipher_dec_context) {
  1097. text->utils->free(text->cipher_dec_context);
  1098. text->cipher_dec_context = NULL;
  1099. }
  1100. }
  1101. static int init_rc4(context_t *text,
  1102. unsigned char enckey[16],
  1103. unsigned char deckey[16])
  1104. {
  1105. /* allocate rc4 context structures */
  1106. text->cipher_enc_context=
  1107. (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
  1108. if (text->cipher_enc_context == NULL) return SASL_NOMEM;
  1109. text->cipher_dec_context=
  1110. (cipher_context_t *) text->utils->malloc(sizeof(rc4_context_t));
  1111. if (text->cipher_dec_context == NULL) return SASL_NOMEM;
  1112. /* initialize them */
  1113. rc4_init((rc4_context_t *) text->cipher_enc_context,
  1114. (const unsigned char *) enckey, 16);
  1115. rc4_init((rc4_context_t *) text->cipher_dec_context,
  1116. (const unsigned char *) deckey, 16);
  1117. return SASL_OK;
  1118. }
  1119. static int dec_rc4(context_t *text,
  1120. const char *input,
  1121. unsigned inputlen,
  1122. unsigned char digest[16] __attribute__((unused)),
  1123. char *output,
  1124. unsigned *outputlen)
  1125. {
  1126. /* decrypt the text part & HMAC */
  1127. rc4_decrypt((rc4_context_t *) text->cipher_dec_context,
  1128. input, output, inputlen);
  1129. /* no padding so we just subtract the HMAC to get the text length */
  1130. *outputlen = inputlen - 10;
  1131. return SASL_OK;
  1132. }
  1133. static int enc_rc4(context_t *text,
  1134. const char *input,
  1135. unsigned inputlen,
  1136. unsigned char digest[16],
  1137. char *output,
  1138. unsigned *outputlen)
  1139. {
  1140. /* pad is zero */
  1141. *outputlen = inputlen+10;
  1142. /* encrypt the text part */
  1143. rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
  1144. input,
  1145. output,
  1146. inputlen);
  1147. /* encrypt the HMAC part */
  1148. rc4_encrypt((rc4_context_t *) text->cipher_enc_context,
  1149. (const char *) digest,
  1150. (output)+inputlen, 10);
  1151. return SASL_OK;
  1152. }
  1153. #endif /* HAVE_OPENSSL */
  1154. #endif /* WITH_RC4 */
  1155. struct digest_cipher available_ciphers[] =
  1156. {
  1157. #ifdef WITH_RC4
  1158. { "rc4-40", 40, 5, 0x01, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
  1159. { "rc4-56", 56, 7, 0x02, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
  1160. { "rc4", 128, 16, 0x04, &enc_rc4, &dec_rc4, &init_rc4, &free_rc4 },
  1161. #endif
  1162. #ifdef WITH_DES
  1163. { "des", 55, 16, 0x08, &enc_des, &dec_des, &init_des, &free_des },
  1164. { "3des", 112, 16, 0x10, &enc_3des, &dec_3des, &init_3des, &free_des },
  1165. #endif
  1166. { NULL, 0, 0, 0, NULL, NULL, NULL, NULL }
  1167. };
  1168. static int create_layer_keys(context_t *text,
  1169. const sasl_utils_t *utils,
  1170. HASH key, int keylen,
  1171. unsigned char enckey[16],
  1172. unsigned char deckey[16])
  1173. {
  1174. MD5_CTX Md5Ctx;
  1175. utils->log(utils->conn, SASL_LOG_DEBUG,
  1176. "DIGEST-MD5 create_layer_keys()");
  1177. utils->MD5Init(&Md5Ctx);
  1178. utils->MD5Update(&Md5Ctx, key, keylen);
  1179. if (text->i_am == SERVER) {
  1180. utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
  1181. (unsigned) strlen(SEALING_SERVER_CLIENT));
  1182. } else {
  1183. utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
  1184. (unsigned) strlen(SEALING_CLIENT_SERVER));
  1185. }
  1186. utils->MD5Final(enckey, &Md5Ctx);
  1187. utils->MD5Init(&Md5Ctx);
  1188. utils->MD5Update(&Md5Ctx, key, keylen);
  1189. if (text->i_am != SERVER) {
  1190. utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_SERVER_CLIENT,
  1191. (unsigned) strlen(SEALING_SERVER_CLIENT));
  1192. } else {
  1193. utils->MD5Update(&Md5Ctx, (const unsigned char *) SEALING_CLIENT_SERVER,
  1194. (unsigned) strlen(SEALING_CLIENT_SERVER));
  1195. }
  1196. utils->MD5Final(deckey, &Md5Ctx);
  1197. /* create integrity keys */
  1198. /* sending */
  1199. utils->MD5Init(&Md5Ctx);
  1200. utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
  1201. if (text->i_am == SERVER) {
  1202. utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
  1203. (unsigned) strlen(SIGNING_SERVER_CLIENT));
  1204. } else {
  1205. utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
  1206. (unsigned) strlen(SIGNING_CLIENT_SERVER));
  1207. }
  1208. utils->MD5Final(text->Ki_send, &Md5Ctx);
  1209. /* receiving */
  1210. utils->MD5Init(&Md5Ctx);
  1211. utils->MD5Update(&Md5Ctx, text->HA1, HASHLEN);
  1212. if (text->i_am != SERVER) {
  1213. utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_SERVER_CLIENT,
  1214. (unsigned) strlen(SIGNING_SERVER_CLIENT));
  1215. } else {
  1216. utils->MD5Update(&Md5Ctx, (const unsigned char *)SIGNING_CLIENT_SERVER,
  1217. (unsigned) strlen(SIGNING_CLIENT_SERVER));
  1218. }
  1219. utils->MD5Final(text->Ki_receive, &Md5Ctx);
  1220. return SASL_OK;
  1221. }
  1222. static const unsigned short version = 1;
  1223. /*
  1224. * privacy:
  1225. * len, CIPHER(Kc, {msg, pag, HMAC(ki, {SeqNum, msg})[0..9]}), x0001, SeqNum
  1226. *
  1227. * integrity:
  1228. * len, HMAC(ki, {SeqNum, msg})[0..9], x0001, SeqNum
  1229. */
  1230. static int digestmd5_encode(void *context,
  1231. const struct iovec *invec,
  1232. unsigned numiov,
  1233. const char **output,
  1234. unsigned *outputlen)
  1235. {
  1236. context_t *text = (context_t *) context;
  1237. int tmp;
  1238. unsigned int tmpnum;
  1239. unsigned short int tmpshort;
  1240. int ret;
  1241. char *out;
  1242. struct buffer_info *inblob, bufinfo;
  1243. if(!context || !invec || !numiov || !output || !outputlen) {
  1244. if (text) PARAMERROR(text->utils);
  1245. return SASL_BADPARAM;
  1246. }
  1247. if (numiov > 1) {
  1248. ret = _plug_iovec_to_buf(text->utils, invec, numiov, &text->enc_in_buf);
  1249. if (ret != SASL_OK) return ret;
  1250. inblob = text->enc_in_buf;
  1251. } else {
  1252. /* avoid the data copy */
  1253. bufinfo.data = invec[0].iov_base;
  1254. bufinfo.curlen = invec[0].iov_len;
  1255. inblob = &bufinfo;
  1256. }
  1257. /* make sure the output buffer is big enough for this blob */
  1258. ret = _plug_buf_alloc(text->utils, &(text->encode_buf),
  1259. &(text->encode_buf_len),
  1260. (4 + /* for length */
  1261. inblob->curlen + /* for content */
  1262. 10 + /* for MAC */
  1263. 8 + /* maximum pad */
  1264. 6)); /* for ver and seqnum */
  1265. if(ret != SASL_OK) return ret;
  1266. /* skip by the length for now */
  1267. out = (text->encode_buf)+4;
  1268. /* construct (seqnum, msg)
  1269. *
  1270. * Use the output buffer so that the message text is already in place
  1271. * for an integrity-only layer.
  1272. */
  1273. tmpnum = htonl(text->seqnum);
  1274. memcpy(text->encode_buf, &tmpnum, 4);
  1275. memcpy(text->encode_buf + 4, inblob->data, inblob->curlen);
  1276. if (text->cipher_enc) {
  1277. unsigned char digest[16];
  1278. /* HMAC(ki, (seqnum, msg) ) */
  1279. text->utils->hmac_md5((const unsigned char *) text->encode_buf,
  1280. inblob->curlen + 4,
  1281. text->Ki_send, HASHLEN, digest);
  1282. /* calculate the encrypted part */
  1283. text->cipher_enc(text, inblob->data, inblob->curlen,
  1284. digest, out, outputlen);
  1285. out+=(*outputlen);
  1286. }
  1287. else {
  1288. /* HMAC(ki, (seqnum, msg) ) -- put directly into output buffer */
  1289. text->utils->hmac_md5((const unsigned char *) text->encode_buf,
  1290. inblob->curlen + 4,
  1291. text->Ki_send, HASHLEN,
  1292. (unsigned char *) text->encode_buf +
  1293. inblob->curlen + 4);
  1294. *outputlen = inblob->curlen + 10; /* for message + CMAC */
  1295. out+=inblob->curlen + 10;
  1296. }
  1297. /* copy in version */
  1298. tmpshort = htons(version);
  1299. memcpy(out, &tmpshort, 2); /* 2 bytes = version */
  1300. out+=2;
  1301. (*outputlen)+=2; /* for version */
  1302. /* put in seqnum */
  1303. tmpnum = htonl(text->seqnum);
  1304. memcpy(out, &tmpnum, 4); /* 4 bytes = seq # */
  1305. (*outputlen)+=4; /* for seqnum */
  1306. /* put the 1st 4 bytes in */
  1307. tmp=htonl(*outputlen);
  1308. memcpy(text->encode_buf, &tmp, 4);
  1309. (*outputlen)+=4;
  1310. *output = text->encode_buf;
  1311. text->seqnum++;
  1312. return SASL_OK;
  1313. }
  1314. static int digestmd5_decode_packet(void *context,
  1315. const char *input,
  1316. unsigned inputlen,
  1317. char **output,
  1318. unsigned *outputlen)
  1319. {
  1320. context_t *text = (context_t *) context;
  1321. int result;
  1322. unsigned char *digest;
  1323. int tmpnum;
  1324. int lup;
  1325. unsigned short ver;
  1326. unsigned int seqnum;
  1327. unsigned char checkdigest[16];
  1328. if (inputlen < 16) {
  1329. text->utils->seterror(text->utils->conn, 0, "DIGEST-MD5 SASL packets must be at least 16 bytes long");
  1330. return SASL_FAIL;
  1331. }
  1332. /* check the version number */
  1333. memcpy(&ver, input+inputlen-6, 2);
  1334. ver = ntohs(ver);
  1335. if (ver != version) {
  1336. text->utils->seterror(text->utils->conn, 0, "Wrong Version");
  1337. return SASL_FAIL;
  1338. }
  1339. /* check the sequence number */
  1340. memcpy(&seqnum, input+inputlen-4, 4);
  1341. seqnum = ntohl(seqnum);
  1342. if (seqnum != text->rec_seqnum) {
  1343. text->utils->seterror(text->utils->conn, 0,
  1344. "Incorrect Sequence Number: received %u, expected %u",
  1345. seqnum,
  1346. text->rec_seqnum);
  1347. return SASL_FAIL;
  1348. }
  1349. /* allocate a buffer large enough for the output */
  1350. result = _plug_buf_alloc(text->utils, &text->decode_packet_buf,
  1351. &text->decode_packet_buf_len,
  1352. inputlen /* length of message */
  1353. - 6 /* skip ver and seqnum */
  1354. + 4); /* prepend seqnum */
  1355. if (result != SASL_OK) return result;
  1356. /* construct (seqnum, msg) */
  1357. tmpnum = htonl(text->rec_seqnum);
  1358. memcpy(text->decode_packet_buf, &tmpnum, 4);
  1359. text->rec_seqnum++; /* now increment it */
  1360. *output = text->decode_packet_buf + 4; /* skip seqnum */
  1361. if (text->cipher_dec) {
  1362. /* decrypt message & HMAC into output buffer */
  1363. result = text->cipher_dec(text, input, inputlen-6, NULL,
  1364. *output, outputlen);
  1365. if (result != SASL_OK) return result;
  1366. }
  1367. else {
  1368. /* copy message & HMAC into output buffer */
  1369. memcpy(*output, input, inputlen - 6);
  1370. *outputlen = inputlen - 16; /* -16 to skip HMAC, ver and seqnum */
  1371. }
  1372. digest = (unsigned char *) *output + (inputlen - 16);
  1373. /* check the CMAC */
  1374. /* HMAC(ki, (seqnum, msg) ) */
  1375. text->utils->hmac_md5((const unsigned char *) text->decode_packet_buf,
  1376. (*outputlen) + 4,
  1377. text->Ki_receive, HASHLEN, checkdigest);
  1378. /* now check it */
  1379. for (lup = 0; lup < 10; lup++)
  1380. if (checkdigest[lup] != digest[lup]) {
  1381. text->utils->seterror(text->utils->conn, 0,
  1382. "CMAC doesn't match at byte %d!", lup);
  1383. return SASL_FAIL;
  1384. }
  1385. return SASL_OK;
  1386. }
  1387. static int digestmd5_decode(void *context,
  1388. const char *input, unsigned inputlen,
  1389. const char **output, unsigned *outputlen)
  1390. {
  1391. context_t *text = (context_t *) context;
  1392. int ret;
  1393. ret = _plug_decode(&text->decode_context, input, inputlen,
  1394. &text->decode_buf, &text->decode_buf_len, outputlen,
  1395. digestmd5_decode_packet, text);
  1396. *output = text->decode_buf;
  1397. return ret;
  1398. }
  1399. static void digestmd5_common_mech_dispose(void *conn_context,
  1400. const sasl_utils_t *utils)
  1401. {
  1402. context_t *text = (context_t *) conn_context;
  1403. int lup;
  1404. if (!text || !utils) return;
  1405. utils->log(utils->conn, SASL_LOG_DEBUG,
  1406. "DIGEST-MD5 common mech dispose");
  1407. if (text->authid) utils->free(text->authid);
  1408. if (text->realm) utils->free(text->realm);
  1409. if (text->realms) {
  1410. /* need to free all the realms */
  1411. for (lup = 0; lup < text->realm_cnt; lup++)
  1412. utils->free (text->realms[lup]);
  1413. utils->free(text->realms);
  1414. }
  1415. if (text->nonce) utils->free(text->nonce);
  1416. if (text->cnonce) utils->free(text->cnonce);
  1417. if (text->cipher_free) text->cipher_free(text);
  1418. /* free the stuff in the context */
  1419. if (text->response_value) utils->free(text->response_value);
  1420. _plug_decode_free(&text->decode_context);
  1421. if (text->encode_buf) utils->free(text->encode_buf);
  1422. if (text->decode_buf) utils->free(text->decode_buf);
  1423. if (text->decode_packet_buf) utils->free(text->decode_packet_buf);
  1424. if (text->out_buf) utils->free(text->out_buf);
  1425. if (text->enc_in_buf) {
  1426. if (text->enc_in_buf->data) utils->free(text->enc_in_buf->data);
  1427. utils->free(text->enc_in_buf);
  1428. }
  1429. utils->free(conn_context);
  1430. }
  1431. static void clear_reauth_entry(reauth_entry_t *reauth, enum Context_type type,
  1432. const sasl_utils_t *utils)
  1433. {
  1434. if (!reauth) return;
  1435. if (reauth->authid) utils->free(reauth->authid);
  1436. if (reauth->realm) utils->free(reauth->realm);
  1437. if (reauth->nonce) utils->free(reauth->nonce);
  1438. if (reauth->cnonce) utils->free(reauth->cnonce);
  1439. if (type == CLIENT) {
  1440. if (reauth->u.c.serverFQDN) utils->free(reauth->u.c.serverFQDN);
  1441. }
  1442. memset(reauth, 0, sizeof(reauth_entry_t));
  1443. }
  1444. static void digestmd5_common_mech_free(void *glob_context,
  1445. const sasl_utils_t *utils)
  1446. {
  1447. digest_glob_context_t *my_glob_context =
  1448. (digest_glob_context_t *) glob_context;
  1449. reauth_cache_t *reauth_cache = my_glob_context->reauth;
  1450. size_t n;
  1451. utils->log(utils->conn, SASL_LOG_DEBUG,
  1452. "DIGEST-MD5 common mech free");
  1453. /* Prevent anybody else from freeing this as well */
  1454. my_glob_context->reauth = NULL;
  1455. if (!reauth_cache) return;
  1456. for (n = 0; n < reauth_cache->size; n++) {
  1457. clear_reauth_entry(&reauth_cache->e[n], reauth_cache->i_am, utils);
  1458. }
  1459. if (reauth_cache->e) utils->free(reauth_cache->e);
  1460. if (reauth_cache->mutex) {
  1461. utils->mutex_free(reauth_cache->mutex);
  1462. reauth_cache->mutex = NULL;
  1463. }
  1464. utils->free(reauth_cache);
  1465. }
  1466. /***************************** Server Section *****************************/
  1467. typedef struct server_context {
  1468. context_t common;
  1469. time_t timestamp;
  1470. int stale; /* last nonce is stale */
  1471. sasl_ssf_t limitssf, requiressf; /* application defined bounds */
  1472. } server_context_t;
  1473. static digest_glob_context_t server_glob_context;
  1474. static void DigestCalcHA1FromSecret(context_t * text,
  1475. const sasl_utils_t * utils,
  1476. HASH HA1,
  1477. unsigned char *authorization_id,
  1478. unsigned char *pszNonce,
  1479. unsigned char *pszCNonce,
  1480. HASHHEX SessionKey)
  1481. {
  1482. MD5_CTX Md5Ctx;
  1483. /* calculate session key */
  1484. utils->MD5Init(&Md5Ctx);
  1485. if (text->http_mode) {
  1486. /* per RFC 2617 Errata ID 1649 */
  1487. HASHHEX HA1Hex;
  1488. CvtHex(HA1, HA1Hex);
  1489. utils->MD5Update(&Md5Ctx, HA1Hex, HASHHEXLEN);
  1490. }
  1491. else {
  1492. /* per RFC 2831 */
  1493. utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
  1494. }
  1495. utils->MD5Update(&Md5Ctx, COLON, 1);
  1496. utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
  1497. utils->MD5Update(&Md5Ctx, COLON, 1);
  1498. utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
  1499. if (authorization_id != NULL) {
  1500. utils->MD5Update(&Md5Ctx, COLON, 1);
  1501. utils->MD5Update(&Md5Ctx, authorization_id,
  1502. (unsigned) strlen((char *) authorization_id));
  1503. }
  1504. utils->MD5Final(HA1, &Md5Ctx);
  1505. CvtHex(HA1, SessionKey);
  1506. /* save HA1 because we need it to make the privacy and integrity keys */
  1507. memcpy(text->HA1, HA1, sizeof(HASH));
  1508. }
  1509. static char *create_response(context_t * text,
  1510. const sasl_utils_t * utils,
  1511. unsigned char *nonce,
  1512. unsigned int ncvalue,
  1513. unsigned char *cnonce,
  1514. char *qop,
  1515. const sasl_http_request_t *request,
  1516. HASH Secret,
  1517. char *authorization_id,
  1518. char **response_value)
  1519. {
  1520. HASHHEX SessionKey;
  1521. HASH EntityHash;
  1522. HASHHEX HEntity;
  1523. HASHHEX Response;
  1524. char *result;
  1525. if (qop == NULL) qop = "auth";
  1526. DigestCalcHA1FromSecret(text,
  1527. utils,
  1528. Secret,
  1529. (unsigned char *) authorization_id,
  1530. nonce,
  1531. cnonce,
  1532. SessionKey);
  1533. if (text->http_mode) {
  1534. /* per RFC 2617 */
  1535. MD5_CTX Md5Ctx;
  1536. utils->MD5Init(&Md5Ctx);
  1537. utils->MD5Update(&Md5Ctx, request->entity, request->elen);
  1538. utils->MD5Final(EntityHash, &Md5Ctx);
  1539. }
  1540. else {
  1541. /* per RFC 2831 */
  1542. memset(EntityHash, 0, HASHLEN);
  1543. }
  1544. CvtHex(EntityHash, HEntity);
  1545. /* Calculate response for comparison with client's response */
  1546. DigestCalcResponse(utils,
  1547. SessionKey,/* HEX(H(A1)) */
  1548. nonce, /* nonce from server */
  1549. ncvalue, /* 8 hex digits */
  1550. cnonce, /* client nonce */
  1551. (unsigned char *) qop, /* qop-value: "", "auth",
  1552. * "auth-int" */
  1553. (unsigned char *) request->uri, /* requested URL */
  1554. (unsigned char *) request->method,
  1555. HEntity, /* H(entity body) if qop="auth-int" */
  1556. Response /* request-digest or response-digest */
  1557. );
  1558. result = utils->malloc(HASHHEXLEN + 1);
  1559. memcpy(result, Response, HASHHEXLEN);
  1560. result[HASHHEXLEN] = 0;
  1561. /* Calculate response value for mutual auth with the client (NO Method) */
  1562. if (response_value != NULL) {
  1563. char * new_response_value;
  1564. DigestCalcResponse(utils,
  1565. SessionKey, /* HEX(H(A1)) */
  1566. nonce, /* nonce from server */
  1567. ncvalue, /* 8 hex digits */
  1568. cnonce, /* client nonce */
  1569. (unsigned char *) qop, /* qop-value: "", "auth",
  1570. * "auth-int" */
  1571. (unsigned char *) request->uri, /* requested URL */
  1572. NULL,
  1573. HEntity, /* H(entity body) if qop="auth-int" */
  1574. Response /* request-digest or response-digest */
  1575. );
  1576. new_response_value = utils->realloc(*response_value, HASHHEXLEN + 1);
  1577. if (new_response_value == NULL) {
  1578. free (*response_value);
  1579. *response_value = NULL;
  1580. return NULL;
  1581. }
  1582. *response_value = new_response_value;
  1583. memcpy(*response_value, Response, HASHHEXLEN);
  1584. (*response_value)[HASHHEXLEN] = 0;
  1585. }
  1586. return result;
  1587. }
  1588. static int get_server_realm(sasl_server_params_t * params, char **realm)
  1589. {
  1590. /* look at user realm first */
  1591. if (params->user_realm != NULL) {
  1592. if(params->user_realm[0] != '\0') {
  1593. *realm = (char *) params->user_realm;
  1594. } else {
  1595. /* Catch improperly converted apps */
  1596. params->utils->seterror(params->utils->conn, 0,
  1597. "user_realm is an empty string!");
  1598. return SASL_BADPARAM;
  1599. }
  1600. } else if (params->serverFQDN != NULL) {
  1601. *realm = (char *) params->serverFQDN;
  1602. } else {
  1603. params->utils->seterror(params->utils->conn, 0,
  1604. "no way to obtain DIGEST-MD5 realm");
  1605. return SASL_FAIL;
  1606. }
  1607. return SASL_OK;
  1608. }
  1609. /*
  1610. * Convert hex string to int
  1611. */
  1612. static int htoi(unsigned char *hexin, unsigned int *res)
  1613. {
  1614. size_t lup, inlen;
  1615. inlen = strlen((char *) hexin);
  1616. *res = 0;
  1617. for (lup = 0; lup < inlen; lup++) {
  1618. switch (hexin[lup]) {
  1619. case '0':
  1620. case '1':
  1621. case '2':
  1622. case '3':
  1623. case '4':
  1624. case '5':
  1625. case '6':
  1626. case '7':
  1627. case '8':
  1628. case '9':
  1629. *res = (*res << 4) + (hexin[lup] - '0');
  1630. break;
  1631. case 'a':
  1632. case 'b':
  1633. case 'c':
  1634. case 'd':
  1635. case 'e':
  1636. case 'f':
  1637. *res = (*res << 4) + (hexin[lup] - 'a' + 10);
  1638. break;
  1639. case 'A':
  1640. case 'B':
  1641. case 'C':
  1642. case 'D':
  1643. case 'E':
  1644. case 'F':
  1645. *res = (*res << 4) + (hexin[lup] - 'A' + 10);
  1646. break;
  1647. default:
  1648. return SASL_BADPARAM;
  1649. }
  1650. }
  1651. return SASL_OK;
  1652. }
  1653. static int digestmd5_server_mech_new(void *glob_context,
  1654. sasl_server_params_t * sparams,
  1655. const char *challenge __attribute__((unused)),
  1656. unsigned challen __attribute__((unused)),
  1657. void **conn_context)
  1658. {
  1659. context_t *text;
  1660. /* holds state are in -- allocate server size */
  1661. text = sparams->utils->malloc(sizeof(server_context_t));
  1662. if (text == NULL)
  1663. return SASL_NOMEM;
  1664. memset((server_context_t *)text, 0, sizeof(server_context_t));
  1665. text->state = 1;
  1666. text->i_am = SERVER;
  1667. text->http_mode = (sparams->flags & SASL_NEED_HTTP);
  1668. text->reauth = ((digest_glob_context_t *) glob_context)->reauth;
  1669. *conn_context = text;
  1670. return SASL_OK;
  1671. }
  1672. static int
  1673. digestmd5_server_mech_step1(server_context_t *stext,
  1674. sasl_server_params_t *sparams,
  1675. const char *clientin __attribute__((unused)),
  1676. unsigned clientinlen __attribute__((unused)),
  1677. const char **serverout,
  1678. unsigned *serveroutlen,
  1679. sasl_out_params_t * oparams __attribute__((unused)))
  1680. {
  1681. context_t *text = (context_t *) stext;
  1682. int result;
  1683. char *realm;
  1684. unsigned char *nonce;
  1685. char *charset = "utf-8";
  1686. char qop[1024], cipheropts[1024];
  1687. struct digest_cipher *cipher;
  1688. unsigned resplen;
  1689. int added_conf = 0;
  1690. char maxbufstr[64];
  1691. sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
  1692. "DIGEST-MD5 server step 1");
  1693. /* get realm */
  1694. result = get_server_realm(sparams, &realm);
  1695. if(result != SASL_OK) return result;
  1696. /* what options should we offer the client? */
  1697. qop[0] = '\0';
  1698. cipheropts[0] = '\0';
  1699. if (stext->requiressf == 0) {
  1700. if (*qop) strcat(qop, ",");
  1701. strcat(qop, "auth");
  1702. }
  1703. if (stext->requiressf <= 1 && stext->limitssf >= 1) {
  1704. if (*qop) strcat(qop, ",");
  1705. strcat(qop, "auth-int");
  1706. }
  1707. cipher = available_ciphers;
  1708. while (cipher->name) {
  1709. /* do we allow this particular cipher? */
  1710. if (stext->requiressf <= cipher->ssf &&
  1711. stext->limitssf >= cipher->ssf) {
  1712. if (!added_conf) {
  1713. if (*qop) strcat(qop, ",");
  1714. strcat(qop, "auth-conf");
  1715. added_conf = 1;
  1716. }
  1717. if (strlen(cipheropts) + strlen(cipher->name) + 1 >= 1024)
  1718. return SASL_FAIL;
  1719. if (*cipheropts) strcat(cipheropts, ",");
  1720. strcat(cipheropts, cipher->name);
  1721. }
  1722. cipher++;
  1723. }
  1724. if (*qop == '\0') {
  1725. /* we didn't allow anything?!? we'll return SASL_TOOWEAK, since
  1726. that's close enough */
  1727. return SASL_TOOWEAK;
  1728. }
  1729. /*
  1730. * digest-challenge = 1#( realm | nonce | qop-options | stale | maxbuf |
  1731. * charset | cipher-opts | auth-param )
  1732. */
  1733. nonce = create_nonce(sparams->utils);
  1734. if (nonce == NULL) {
  1735. SETERROR(sparams->utils, "internal erorr: failed creating a nonce");
  1736. return SASL_FAIL;
  1737. }
  1738. resplen = 0;
  1739. text->out_buf = NULL;
  1740. text->out_buf_len = 0;
  1741. if (add_to_challenge(sparams->utils,
  1742. &text->out_buf, &text->out_buf_len, &resplen,
  1743. "nonce", (unsigned char *) nonce,
  1744. TRUE) != SASL_OK) {
  1745. SETERROR(sparams->utils, "internal error: add_to_challenge failed");
  1746. return SASL_FAIL;
  1747. }
  1748. /* add to challenge; if we chose not to specify a realm, we won't
  1749. * send one to the client */
  1750. if (realm && add_to_challenge(sparams->utils,
  1751. &text->out_buf, &text->out_buf_len, &resplen,
  1752. "realm", (unsigned char *) realm,
  1753. TRUE) != SASL_OK) {
  1754. SETERROR(sparams->utils, "internal error: add_to_challenge failed");
  1755. return SASL_FAIL;
  1756. }
  1757. /*
  1758. * qop-options A quoted string of one or more tokens indicating the
  1759. * "quality of protection" values supported by the server. The value
  1760. * "auth" indicates authentication; the value "auth-int" indicates
  1761. * authentication with integrity protection; the value "auth-conf"
  1762. * indicates authentication with integrity protection and encryption.
  1763. */
  1764. /* add qop to challenge */
  1765. if (add_to_challenge(sparams->utils,
  1766. &text->out_buf, &text->out_buf_len, &resplen,
  1767. "qop",
  1768. (unsigned char *) qop, TRUE) != SASL_OK) {
  1769. SETERROR(sparams->utils, "internal error: add_to_challenge 3 failed");
  1770. return SASL_FAIL;
  1771. }
  1772. /*
  1773. * Cipheropts - list of ciphers server supports
  1774. */
  1775. /* add cipher-opts to challenge; only add if there are some */
  1776. if (strcmp(cipheropts,"")!=0)
  1777. {
  1778. if (add_to_challenge(sparams->utils,
  1779. &text->out_buf, &text->out_buf_len, &resplen,
  1780. "cipher", (unsigned char *) cipheropts,
  1781. TRUE) != SASL_OK) {
  1782. SETERROR(sparams->utils,
  1783. "internal error: add_to_challenge 4 failed");
  1784. return SASL_FAIL;
  1785. }
  1786. }
  1787. /* "stale" is true if a reauth failed because of a nonce timeout */
  1788. if (stext->stale &&
  1789. add_to_challenge(sparams->utils,
  1790. &text->out_buf, &text->out_buf_len, &resplen,
  1791. "stale", (unsigned char *) "true", FALSE) != SASL_OK) {
  1792. SETERROR(sparams->utils, "internal error: add_to_challenge failed");
  1793. return SASL_FAIL;
  1794. }
  1795. /*
  1796. * maxbuf A number indicating the size of the largest buffer the server
  1797. * is able to receive when using "auth-int". If this directive is
  1798. * missing, the default value is 65536. This directive may appear at most
  1799. * once; if multiple instances are present, the client should abort the
  1800. * authentication exchange.
  1801. */
  1802. if(sparams->props.maxbufsize) {
  1803. snprintf(maxbufstr, sizeof(maxbufstr), "%u",
  1804. sparams->props.maxbufsize);
  1805. if (add_to_challenge(sparams->utils,
  1806. &text->out_buf, &text->out_buf_len, &resplen,
  1807. "maxbuf",
  1808. (unsigned char *) maxbufstr, FALSE) != SASL_OK) {
  1809. SETERROR(sparams->utils,
  1810. "internal error: add_to_challenge 5 failed");
  1811. return SASL_FAIL;
  1812. }
  1813. }
  1814. if (add_to_challenge(sparams->utils,
  1815. &text->out_buf, &text->out_buf_len, &resplen,
  1816. "charset",
  1817. (unsigned char *) charset, FALSE) != SASL_OK) {
  1818. SETERROR(sparams->utils, "internal error: add_to_challenge 6 failed");
  1819. return SASL_FAIL;
  1820. }
  1821. /*
  1822. * algorithm
  1823. * This directive is required for backwards compatibility with HTTP
  1824. * Digest, which supports other algorithms. This directive is
  1825. * required and MUST appear exactly once; if not present, or if multiple
  1826. * instances are present, the client should abort the authentication
  1827. * exchange.
  1828. *
  1829. * algorithm = "algorithm" "=" "md5-sess"
  1830. */
  1831. if (add_to_challenge(sparams->utils,
  1832. &text->out_buf, &text->out_buf_len, &resplen,
  1833. "algorithm",
  1834. (unsigned char *) "md5-sess", FALSE)!=SASL_OK) {
  1835. SETERROR(sparams->utils, "internal error: add_to_challenge 7 failed");
  1836. return SASL_FAIL;
  1837. }
  1838. /*
  1839. * The size of a digest-challenge MUST be less than 2048 bytes!!!
  1840. */
  1841. if (*serveroutlen > 2048) {
  1842. SETERROR(sparams->utils,
  1843. "internal error: challenge larger than 2048 bytes");
  1844. return SASL_FAIL;
  1845. }
  1846. text->authid = NULL;
  1847. if (_plug_strdup(sparams->utils, realm, &text->realm, NULL) != SASL_OK) {
  1848. SETERROR(sparams->utils,
  1849. "internal error: out of memory when saving realm");
  1850. return SASL_FAIL;
  1851. }
  1852. if (text->http_mode && text->reauth->timeout &&
  1853. sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
  1854. /* Create an initial cache entry for non-persistent HTTP connections */
  1855. unsigned val = hash((char *) nonce) % text->reauth->size;
  1856. clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
  1857. text->reauth->e[val].authid = NULL;
  1858. text->reauth->e[val].realm = text->realm; text->realm = NULL;
  1859. text->reauth->e[val].nonce = nonce;
  1860. text->reauth->e[val].nonce_count = 1;
  1861. text->reauth->e[val].cnonce = NULL;
  1862. text->reauth->e[val].u.s.timestamp = time(0);
  1863. sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
  1864. }
  1865. else {
  1866. text->nonce = nonce;
  1867. text->nonce_count = 1;
  1868. text->cnonce = NULL;
  1869. stext->timestamp = time(0);
  1870. }
  1871. *serveroutlen = (unsigned) strlen(text->out_buf);
  1872. *serverout = text->out_buf;
  1873. text->state = 2;
  1874. return SASL_CONTINUE;
  1875. }
  1876. static int digestmd5_server_mech_step2(server_context_t *stext,
  1877. sasl_server_params_t *sparams,
  1878. const char *clientin,
  1879. unsigned clientinlen,
  1880. const char **serverout,
  1881. unsigned *serveroutlen,
  1882. sasl_out_params_t * oparams)
  1883. {
  1884. context_t *text = (context_t *) stext;
  1885. /* verify digest */
  1886. sasl_secret_t *sec = NULL;
  1887. int result;
  1888. char *serverresponse = NULL;
  1889. char *username = NULL;
  1890. char *authorization_id = NULL;
  1891. char *realm = NULL;
  1892. unsigned char *nonce = NULL, *cnonce = NULL;
  1893. unsigned int noncecount = 0;
  1894. char *qop = NULL;
  1895. char *digesturi = NULL;
  1896. sasl_http_request_t rfc2831_request;
  1897. const sasl_http_request_t *request;
  1898. char *response = NULL;
  1899. /* setting the default value (65536) */
  1900. unsigned long client_maxbuf = 65536;
  1901. int maxbuf_count = 0; /* How many maxbuf instances was found */
  1902. char *charset = NULL;
  1903. char *cipher = NULL;
  1904. unsigned int n = 0;
  1905. HASH Secret;
  1906. HASH SecretBogus;
  1907. bool Try_8859_1 = FALSE;
  1908. int client_ignores_realm = 0;
  1909. char *full_username = NULL;
  1910. char *internal_username = NULL;
  1911. int canon_flags;
  1912. /* password prop_request */
  1913. const char *password_request[] = { SASL_AUX_PASSWORD,
  1914. #if defined(OBSOLETE_DIGEST_ATTR)
  1915. "*cmusaslsecretDIGEST-MD5",
  1916. #endif
  1917. NULL };
  1918. size_t len;
  1919. struct propval auxprop_values[2];
  1920. /* can we mess with clientin? copy it to be safe */
  1921. char *in_start = NULL;
  1922. char *in = NULL;
  1923. cipher_free_t *old_cipher_free = NULL;
  1924. sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
  1925. "DIGEST-MD5 server step 2");
  1926. if (clientinlen == 0) {
  1927. SETERROR(sparams->utils, "input expected in DIGEST-MD5, step 2");
  1928. result = SASL_BADAUTH;
  1929. goto FreeAllMem;
  1930. }
  1931. if (text->http_mode) {
  1932. /* per RFC 2617 (HTTP Request as set by calling application) */
  1933. request = sparams->http_request;
  1934. if (!request) {
  1935. SETERROR(sparams->utils,
  1936. "missing HTTP request in DIGEST-MD5, step 2");
  1937. result = SASL_BADPARAM;
  1938. goto FreeAllMem;
  1939. }
  1940. }
  1941. else {
  1942. /* per RFC 2831 */
  1943. rfc2831_request.method = "AUTHENTICATE";
  1944. rfc2831_request.uri = NULL; /* to be filled in below from response */
  1945. rfc2831_request.entity = NULL;
  1946. rfc2831_request.elen = 0;
  1947. rfc2831_request.non_persist = 0;
  1948. request = &rfc2831_request;
  1949. }
  1950. in = sparams->utils->malloc(clientinlen + 1);
  1951. memcpy(in, clientin, clientinlen);
  1952. in[clientinlen] = 0;
  1953. in_start = in;
  1954. /* parse what we got */
  1955. while (in[0] != '\0') {
  1956. char *name = NULL, *value = NULL;
  1957. get_pair(&in, &name, &value);
  1958. if (name == NULL) {
  1959. SETERROR(sparams->utils,
  1960. "Parse error");
  1961. result = SASL_BADAUTH;
  1962. goto FreeAllMem;
  1963. }
  1964. if (*name == '\0') {
  1965. break;
  1966. }
  1967. /* Extracting parameters */
  1968. /*
  1969. * digest-response = 1#( username | realm | nonce | cnonce |
  1970. * nonce-count | qop | digest-uri | response | maxbuf | charset |
  1971. * cipher | auth-param )
  1972. */
  1973. if (strcasecmp(name, "username") == 0) {
  1974. _plug_strdup(sparams->utils, value, &username, NULL);
  1975. } else if (strcasecmp(name, "authzid") == 0) {
  1976. _plug_strdup(sparams->utils, value, &authorization_id, NULL);
  1977. } else if (strcasecmp(name, "cnonce") == 0) {
  1978. _plug_strdup(sparams->utils, value, (char **) &cnonce, NULL);
  1979. } else if (strcasecmp(name, "nc") == 0) {
  1980. if (htoi((unsigned char *) value, &noncecount) != SASL_OK) {
  1981. SETERROR(sparams->utils,
  1982. "error converting hex to int");
  1983. result = SASL_BADAUTH;
  1984. goto FreeAllMem;
  1985. }
  1986. } else if (strcasecmp(name, "realm") == 0) {
  1987. if (realm) {
  1988. SETERROR(sparams->utils,
  1989. "duplicate realm: authentication aborted");
  1990. result = SASL_FAIL;
  1991. goto FreeAllMem;
  1992. }
  1993. _plug_strdup(sparams->utils, value, &realm, NULL);
  1994. } else if (strcasecmp(name, "nonce") == 0) {
  1995. _plug_strdup(sparams->utils, value, (char **) &nonce, NULL);
  1996. } else if (strcasecmp(name, "qop") == 0) {
  1997. if (qop) {
  1998. SETERROR(sparams->utils,
  1999. "duplicate qop: authentication aborted");
  2000. result = SASL_FAIL;
  2001. goto FreeAllMem;
  2002. }
  2003. _plug_strdup(sparams->utils, value, &qop, NULL);
  2004. } else if (strcasecmp(name, "digest-uri") == 0 || /* per RFC 2831 */
  2005. (text->http_mode &&
  2006. strcasecmp(name, "uri") == 0)) { /* per RFC 2617 */
  2007. size_t service_len;
  2008. if (digesturi) {
  2009. SETERROR(sparams->utils,
  2010. "duplicate digest-uri: authentication aborted");
  2011. result = SASL_FAIL;
  2012. goto FreeAllMem;
  2013. }
  2014. _plug_strdup(sparams->utils, value, &digesturi, NULL);
  2015. if (text->http_mode && request && request->uri) {
  2016. /* Verify digest-uri matches HTTP request (per RFC 2617) */
  2017. if (strcmp(digesturi, request->uri)) {
  2018. result = SASL_BADAUTH;
  2019. SETERROR(sparams->utils,
  2020. "bad digest-uri: doesn't match HTTP request");
  2021. goto FreeAllMem;
  2022. }
  2023. }
  2024. else {
  2025. /* Verify digest-uri format (per RFC 2831):
  2026. *
  2027. * digest-uri-value = serv-type "/" host [ "/" serv-name ]
  2028. */
  2029. /* make sure it's the service that we're expecting */
  2030. service_len = strlen(sparams->service);
  2031. if (strncasecmp(digesturi, sparams->service, service_len) ||
  2032. digesturi[service_len] != '/') {
  2033. result = SASL_BADAUTH;
  2034. SETERROR(sparams->utils,
  2035. "bad digest-uri: doesn't match service");
  2036. goto FreeAllMem;
  2037. }
  2038. /* xxx we don't verify the hostname component */
  2039. rfc2831_request.uri = digesturi;
  2040. }
  2041. } else if (strcasecmp(name, "response") == 0) {
  2042. _plug_strdup(sparams->utils, value, &response, NULL);
  2043. } else if (strcasecmp(name, "cipher") == 0) {
  2044. _plug_strdup(sparams->utils, value, &cipher, NULL);
  2045. } else if (strcasecmp(name, "maxbuf") == 0) {
  2046. maxbuf_count++;
  2047. if (maxbuf_count != 1) {
  2048. result = SASL_BADAUTH;
  2049. SETERROR(sparams->utils,
  2050. "duplicate maxbuf: authentication aborted");
  2051. goto FreeAllMem;
  2052. } else if (str2ul32 (value, &client_maxbuf) == FALSE) {
  2053. result = SASL_BADAUTH;
  2054. SETERROR(sparams->utils, "invalid maxbuf parameter");
  2055. goto FreeAllMem;
  2056. } else {
  2057. if (client_maxbuf <= 16) {
  2058. result = SASL_BADAUTH;
  2059. SETERROR(sparams->utils,
  2060. "maxbuf parameter too small");
  2061. goto FreeAllMem;
  2062. }
  2063. if (client_maxbuf > MAX_SASL_BUFSIZE) {
  2064. result = SASL_BADAUTH;
  2065. SETERROR(sparams->utils,
  2066. "maxbuf parameter too big");
  2067. goto FreeAllMem;
  2068. }
  2069. }
  2070. } else if (strcasecmp(name, "charset") == 0) {
  2071. if (strcasecmp(value, "utf-8") != 0) {
  2072. SETERROR(sparams->utils, "client doesn't support UTF-8");
  2073. result = SASL_FAIL;
  2074. goto FreeAllMem;
  2075. }
  2076. _plug_strdup(sparams->utils, value, &charset, NULL);
  2077. } else if (strcasecmp(name,"algorithm") == 0) {
  2078. /* per RFC 2831: algorithm MUST be ignored if received */
  2079. if (text->http_mode && strcasecmp(value, "md5-sess") != 0) {
  2080. /* per RFC 2617: algorithm MUST match that sent in challenge */
  2081. SETERROR(sparams->utils, "'algorithm' isn't 'md5-sess'");
  2082. result = SASL_FAIL;
  2083. goto FreeAllMem;
  2084. }
  2085. } else {
  2086. sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
  2087. "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
  2088. name, value);
  2089. }
  2090. }
  2091. /*
  2092. * username = "username" "=" <"> username-value <">
  2093. * username-value = qdstr-val
  2094. * cnonce = "cnonce" "=" <"> cnonce-value <">
  2095. * cnonce-value = qdstr-val
  2096. * nonce-count = "nc" "=" nc-value
  2097. * nc-value = 8LHEX
  2098. * qop = "qop" "=" qop-value
  2099. * digest-uri = "digest-uri" "=" digest-uri-value
  2100. * digest-uri-value = serv-type "/" host [ "/" serv-name ]
  2101. * serv-type = 1*ALPHA
  2102. * host = 1*( ALPHA | DIGIT | "-" | "." )
  2103. * service = host
  2104. * response = "response" "=" <"> response-value <">
  2105. * response-value = 32LHEX
  2106. * LHEX = "0" | "1" | "2" | "3" | "4" | "5" |
  2107. * "6" | "7" | "8" | "9" | "a" | "b" | "c" | "d" | "e" | "f"
  2108. * cipher = "cipher" "=" cipher-value
  2109. */
  2110. /* Verifing that all required parameters were received */
  2111. if ((username == NULL)) {
  2112. SETERROR(sparams->utils, "required parameters missing: username");
  2113. result = SASL_BADAUTH;
  2114. goto FreeAllMem;
  2115. }
  2116. if ((nonce == NULL)) {
  2117. SETERROR(sparams->utils, "required parameters missing: nonce");
  2118. result = SASL_BADAUTH;
  2119. goto FreeAllMem;
  2120. }
  2121. if ((noncecount == 0)) {
  2122. SETERROR(sparams->utils, "required parameters missing: noncecount");
  2123. result = SASL_BADAUTH;
  2124. goto FreeAllMem;
  2125. }
  2126. if ((cnonce == NULL)) {
  2127. SETERROR(sparams->utils, "required parameters missing: cnonce");
  2128. result = SASL_BADAUTH;
  2129. goto FreeAllMem;
  2130. }
  2131. if ((digesturi == NULL)) {
  2132. SETERROR(sparams->utils, "required parameters missing: digesturi");
  2133. result = SASL_BADAUTH;
  2134. goto FreeAllMem;
  2135. }
  2136. if ((response == NULL)) {
  2137. SETERROR(sparams->utils, "required parameters missing: response");
  2138. result = SASL_BADAUTH;
  2139. goto FreeAllMem;
  2140. }
  2141. if (realm == NULL) {
  2142. /* From 2831bis:
  2143. If the directive is missing, "realm-value" will set to
  2144. the empty string when computing A1. */
  2145. _plug_strdup(sparams->utils, "", &realm, NULL);
  2146. sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
  2147. "The client didn't send a realm, assuming empty string.");
  2148. #if 0
  2149. if (text->realm[0] != '\0') {
  2150. SETERROR(sparams->utils,
  2151. "realm changed: authentication aborted");
  2152. result = SASL_BADAUTH;
  2153. goto FreeAllMem;
  2154. }
  2155. #endif
  2156. }
  2157. if (!text->nonce && text->reauth->timeout && text->reauth->size > 0) {
  2158. unsigned val = hash((char *) nonce) % text->reauth->size;
  2159. /* reauth attempt or continuation of HTTP Digest on a
  2160. non-persistent connection, see if we have any info for this nonce */
  2161. if (sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
  2162. if (text->reauth->e[val].realm &&
  2163. !strcmp(realm, text->reauth->e[val].realm) &&
  2164. ((text->reauth->e[val].nonce_count == 1) ||
  2165. (text->reauth->e[val].authid &&
  2166. !strcmp(username, text->reauth->e[val].authid)))) {
  2167. _plug_strdup(sparams->utils, text->reauth->e[val].realm,
  2168. &text->realm, NULL);
  2169. _plug_strdup(sparams->utils, (char *) text->reauth->e[val].nonce,
  2170. (char **) &text->nonce, NULL);
  2171. text->nonce_count = text->reauth->e[val].nonce_count;
  2172. #if 0 /* XXX Neither RFC 2617 nor RFC 2831 state that the cnonce
  2173. needs to remain constant for subsequent authentication to work */
  2174. _plug_strdup(sparams->utils, (char *) text->reauth->e[val].cnonce,
  2175. (char **) &text->cnonce, NULL);
  2176. #endif
  2177. stext->timestamp = text->reauth->e[val].u.s.timestamp;
  2178. }
  2179. sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
  2180. }
  2181. if (!text->nonce) {
  2182. /* we don't have any reauth info */
  2183. sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
  2184. "No reauth info for '%s' found", nonce);
  2185. /* we will continue processing the response to determine
  2186. if the client knows the password and return stale accordingly */
  2187. }
  2188. }
  2189. /* Sanity check the parameters */
  2190. if (text->nonce) {
  2191. /* CLAIM: realm is not NULL below */
  2192. if (text->realm == NULL) {
  2193. sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
  2194. "The client specifies a realm when the server hasn't provided one. Using client's realm.");
  2195. _plug_strdup(sparams->utils, realm, &text->realm, NULL);
  2196. } else if ((strcmp(realm, text->realm) != 0) &&
  2197. /* XXX - Not sure why the check for text->realm not being empty is needed,
  2198. as it should always be non-empty */
  2199. (text->realm[0] != 0)) {
  2200. client_ignores_realm = 1;
  2201. sparams->utils->log(sparams->utils->conn, SASL_LOG_DEBUG,
  2202. "The client tries to override server provided realm");
  2203. if (text->realm) sparams->utils->free(text->realm);
  2204. _plug_strdup(sparams->utils, realm, &text->realm, NULL);
  2205. }
  2206. if (strcmp((char *) nonce, (char *) text->nonce) != 0) {
  2207. SETERROR(sparams->utils,
  2208. "nonce changed: authentication aborted");
  2209. result = SASL_BADAUTH;
  2210. goto FreeAllMem;
  2211. }
  2212. #if 0 /* XXX Possible replay attack, but we will continue processing
  2213. * the response to determine if the client knows the password and
  2214. return stale accordingly */
  2215. if (noncecount != text->nonce_count) {
  2216. SETERROR(sparams->utils,
  2217. "incorrect nonce-count: authentication aborted");
  2218. result = SASL_BADAUTH;
  2219. goto FreeAllMem;
  2220. }
  2221. #endif
  2222. #if 0 /* XXX Neither RFC 2617 nor RFC 2831 state that the cnonce
  2223. needs to remain constant for subsequent authentication to work */
  2224. if (text->cnonce && strcmp((char *) cnonce, (char *) text->cnonce) != 0) {
  2225. SETERROR(sparams->utils,
  2226. "cnonce changed: authentication aborted");
  2227. result = SASL_BADAUTH;
  2228. goto FreeAllMem;
  2229. }
  2230. #endif
  2231. }
  2232. result = sparams->utils->prop_request(sparams->propctx, password_request);
  2233. if(result != SASL_OK) {
  2234. SETERROR(sparams->utils, "unable to obtain user password");
  2235. goto FreeAllMem;
  2236. }
  2237. /* this will trigger the getting of the aux properties */
  2238. /* Note that if we don't have an authorization id, we don't use it... */
  2239. if (client_ignores_realm) {
  2240. if (strlen(text->realm) == 0) {
  2241. /* Don't put @ at the end of the username, if the realm is empty */
  2242. _plug_strdup(sparams->utils, username, &full_username, NULL);
  2243. } else {
  2244. full_username = (char *) sparams->utils->malloc(strlen(username) +
  2245. strlen(text->realm) + 2);
  2246. full_username[0] = '\0';
  2247. sprintf (full_username, "%s@%s", username, text->realm);
  2248. }
  2249. internal_username = full_username;
  2250. } else {
  2251. internal_username = username;
  2252. }
  2253. canon_flags = SASL_CU_AUTHID;
  2254. if (!authorization_id || !*authorization_id) {
  2255. canon_flags |= SASL_CU_AUTHZID;
  2256. }
  2257. result = sparams->canon_user(sparams->utils->conn,
  2258. internal_username,
  2259. 0,
  2260. canon_flags,
  2261. oparams);
  2262. if (result != SASL_OK) {
  2263. SETERROR(sparams->utils, "unable to canonify user and get auxprops");
  2264. goto FreeAllMem;
  2265. }
  2266. if (authorization_id != NULL && *authorization_id != '\0') {
  2267. result = sparams->canon_user(sparams->utils->conn,
  2268. authorization_id, 0, SASL_CU_AUTHZID,
  2269. oparams);
  2270. }
  2271. if (result != SASL_OK) {
  2272. SETERROR(sparams->utils, "unable to canonify authorization ID");
  2273. goto FreeAllMem;
  2274. }
  2275. result = sparams->utils->prop_getnames(sparams->propctx, password_request,
  2276. auxprop_values);
  2277. if (result < 0 ||
  2278. ((!auxprop_values[0].name || !auxprop_values[0].values)
  2279. #if defined(OBSOLETE_DIGEST_ATTR)
  2280. && (!auxprop_values[1].name || !auxprop_values[1].values)
  2281. #endif
  2282. )) {
  2283. /* We didn't find this username */
  2284. sparams->utils->seterror(sparams->utils->conn, 0,
  2285. "no secret in database");
  2286. result = sparams->transition ? SASL_TRANS : SASL_NOUSER;
  2287. goto FreeAllMem;
  2288. }
  2289. if (auxprop_values[0].name && auxprop_values[0].values) {
  2290. len = strlen(auxprop_values[0].values[0]);
  2291. if (len == 0) {
  2292. sparams->utils->seterror(sparams->utils->conn,0,
  2293. "empty secret");
  2294. result = SASL_FAIL;
  2295. goto FreeAllMem;
  2296. }
  2297. sec = sparams->utils->malloc(sizeof(sasl_secret_t) + len);
  2298. if (!sec) {
  2299. SETERROR(sparams->utils, "unable to allocate secret");
  2300. result = SASL_FAIL;
  2301. goto FreeAllMem;
  2302. }
  2303. sec->len = (unsigned) len;
  2304. strncpy((char *) sec->data, auxprop_values[0].values[0], len + 1);
  2305. /*
  2306. * Verifying response obtained from client
  2307. *
  2308. * H_URP = H({ username-value,":",realm-value,":",passwd}) sec->data
  2309. * contains H_URP
  2310. */
  2311. /* Calculate the secret from the plaintext password */
  2312. {
  2313. /*
  2314. * Secret = { H( { username-value, ":", realm-value, ":", passwd } ) }
  2315. *
  2316. * (used to build A1)
  2317. */
  2318. Try_8859_1 = DigestCalcSecret(sparams->utils,
  2319. (unsigned char *) username,
  2320. (unsigned char *) realm,
  2321. sec->data,
  2322. sec->len,
  2323. FALSE,
  2324. Secret);
  2325. Secret[HASHLEN] = '\0';
  2326. }
  2327. if (Try_8859_1) {
  2328. /*
  2329. * Secret = { H( { username-value, ":", realm-value, ":", passwd } ) }
  2330. *
  2331. * (used to build A1)
  2332. */
  2333. DigestCalcSecret(sparams->utils,
  2334. (unsigned char *) username,
  2335. (unsigned char *) realm,
  2336. sec->data,
  2337. sec->len,
  2338. TRUE,
  2339. SecretBogus);
  2340. SecretBogus[HASHLEN] = '\0';
  2341. }
  2342. /* We're done with sec now. Let's get rid of it */
  2343. _plug_free_secret(sparams->utils, &sec);
  2344. #if defined(OBSOLETE_DIGEST_ATTR)
  2345. } else if (auxprop_values[1].name && auxprop_values[1].values) {
  2346. /* NB: This will most likely fail for clients that
  2347. choose to ignore server-advertised realm */
  2348. memcpy(Secret, auxprop_values[1].values[0], HASHLEN);
  2349. Secret[HASHLEN] = '\0';
  2350. #endif
  2351. } else {
  2352. sparams->utils->seterror(sparams->utils->conn, 0,
  2353. "Have neither type of secret");
  2354. return SASL_FAIL;
  2355. }
  2356. /* erase the plaintext password */
  2357. sparams->utils->prop_erase(sparams->propctx, password_request[0]);
  2358. /* defaulting qop to "auth" if not specified */
  2359. if (qop == NULL) {
  2360. _plug_strdup(sparams->utils, "auth", &qop, NULL);
  2361. }
  2362. if (oparams->mech_ssf > 1) {
  2363. /* Remember the old cipher free function (if any).
  2364. It will be called later, once we are absolutely
  2365. sure that authentication was successful. */
  2366. old_cipher_free = text->cipher_free;
  2367. /* free the old cipher context first */
  2368. }
  2369. /* check which layer/cipher to use */
  2370. if ((!strcasecmp(qop, "auth-conf")) && (cipher != NULL)) {
  2371. /* see what cipher was requested */
  2372. struct digest_cipher *cptr;
  2373. cptr = available_ciphers;
  2374. while (cptr->name) {
  2375. /* find the cipher requested & make sure it's one we're happy
  2376. with by policy */
  2377. if (!strcasecmp(cipher, cptr->name) &&
  2378. stext->requiressf <= cptr->ssf &&
  2379. stext->limitssf >= cptr->ssf) {
  2380. /* found it! */
  2381. break;
  2382. }
  2383. cptr++;
  2384. }
  2385. if (cptr->name) {
  2386. text->cipher_enc = cptr->cipher_enc;
  2387. text->cipher_dec = cptr->cipher_dec;
  2388. text->cipher_init = cptr->cipher_init;
  2389. text->cipher_free = cptr->cipher_free;
  2390. oparams->mech_ssf = cptr->ssf;
  2391. n = cptr->n;
  2392. } else {
  2393. /* erg? client requested something we didn't advertise! */
  2394. sparams->utils->log(sparams->utils->conn, SASL_LOG_WARN,
  2395. "protocol violation: client requested invalid cipher");
  2396. SETERROR(sparams->utils, "client requested invalid cipher");
  2397. /* Mark that we attempted security layer negotiation */
  2398. oparams->mech_ssf = 2;
  2399. result = SASL_FAIL;
  2400. goto FreeAllMem;
  2401. }
  2402. oparams->encode=&digestmd5_encode;
  2403. oparams->decode=&digestmd5_decode;
  2404. } else if (!strcasecmp(qop, "auth-int") &&
  2405. stext->requiressf <= 1 && stext->limitssf >= 1) {
  2406. oparams->encode = &digestmd5_encode;
  2407. oparams->decode = &digestmd5_decode;
  2408. oparams->mech_ssf = 1;
  2409. } else if (!strcasecmp(qop, "auth") && stext->requiressf == 0) {
  2410. oparams->encode = NULL;
  2411. oparams->decode = NULL;
  2412. oparams->mech_ssf = 0;
  2413. } else {
  2414. SETERROR(sparams->utils,
  2415. "protocol violation: client requested invalid qop");
  2416. result = SASL_FAIL;
  2417. goto FreeAllMem;
  2418. }
  2419. serverresponse = create_response(text,
  2420. sparams->utils,
  2421. nonce,
  2422. noncecount,
  2423. cnonce,
  2424. qop,
  2425. request,
  2426. Secret,
  2427. authorization_id,
  2428. &text->response_value);
  2429. if (serverresponse == NULL) {
  2430. SETERROR(sparams->utils, "internal error: unable to create response");
  2431. result = SASL_NOMEM;
  2432. goto FreeAllMem;
  2433. }
  2434. /* if ok verified */
  2435. if (strcmp(serverresponse, response) != 0) {
  2436. if (Try_8859_1) {
  2437. sparams->utils->free(serverresponse);
  2438. serverresponse = create_response(text,
  2439. sparams->utils,
  2440. nonce,
  2441. noncecount,
  2442. cnonce,
  2443. qop,
  2444. request,
  2445. SecretBogus,
  2446. authorization_id,
  2447. &text->response_value);
  2448. if (serverresponse == NULL) {
  2449. SETERROR(sparams->utils, "internal error: unable to create response");
  2450. result = SASL_NOMEM;
  2451. goto FreeAllMem;
  2452. }
  2453. /* if ok verified */
  2454. if (strcmp(serverresponse, response) != 0) {
  2455. SETERROR(sparams->utils,
  2456. "client response doesn't match what we generated (tried bogus)");
  2457. result = SASL_BADAUTH;
  2458. goto FreeAllMem;
  2459. }
  2460. } else {
  2461. SETERROR(sparams->utils,
  2462. "client response doesn't match what we generated");
  2463. result = SASL_BADAUTH;
  2464. goto FreeAllMem;
  2465. }
  2466. }
  2467. /* see if our nonce expired */
  2468. if (!text->nonce ||
  2469. (noncecount != text->nonce_count) ||
  2470. (text->reauth->timeout &&
  2471. time(0) - stext->timestamp > text->reauth->timeout)) {
  2472. if (!text->nonce) SETERROR(sparams->utils, "no cached server nonce");
  2473. else if (noncecount != text->nonce_count)
  2474. SETERROR(sparams->utils, "incorrect nonce-count");
  2475. else SETERROR(sparams->utils, "server nonce expired");
  2476. stext->stale = 1;
  2477. result = SASL_BADAUTH;
  2478. goto FreeAllMem;
  2479. }
  2480. /*
  2481. * nothing more to do; authenticated set oparams information
  2482. */
  2483. oparams->doneflag = 1;
  2484. oparams->maxoutbuf = client_maxbuf - 4;
  2485. if (oparams->mech_ssf > 1) {
  2486. /* MAC block (privacy) */
  2487. oparams->maxoutbuf -= 25;
  2488. } else if(oparams->mech_ssf == 1) {
  2489. /* MAC block (integrity) */
  2490. oparams->maxoutbuf -= 16;
  2491. }
  2492. oparams->param_version = 0;
  2493. text->seqnum = 0; /* for integrity/privacy */
  2494. text->rec_seqnum = 0; /* for integrity/privacy */
  2495. text->utils = sparams->utils;
  2496. /* Free the old security layer, if any */
  2497. if (old_cipher_free) old_cipher_free(text);
  2498. /* used by layers */
  2499. _plug_decode_init(&text->decode_context, text->utils,
  2500. sparams->props.maxbufsize ? sparams->props.maxbufsize :
  2501. DEFAULT_BUFSIZE);
  2502. if (oparams->mech_ssf > 0) {
  2503. unsigned char enckey[16];
  2504. unsigned char deckey[16];
  2505. create_layer_keys(text, sparams->utils,text->HA1,n,enckey,deckey);
  2506. /* initialize cipher if need be */
  2507. if (text->cipher_init) {
  2508. if (text->cipher_init(text, enckey, deckey) != SASL_OK) {
  2509. sparams->utils->seterror(sparams->utils->conn, 0,
  2510. "couldn't init cipher");
  2511. }
  2512. }
  2513. }
  2514. /*
  2515. * The server receives and validates the "digest-response". The server
  2516. * checks that the nonce-count is "00000001". If it supports subsequent
  2517. * authentication, it saves the value of the nonce and the nonce-count.
  2518. */
  2519. /*
  2520. * The "username-value", "realm-value" and "passwd" are encoded according
  2521. * to the value of the "charset" directive. If "charset=UTF-8" is
  2522. * present, and all the characters of either "username-value" or "passwd"
  2523. * are in the ISO 8859-1 character set, then it must be converted to
  2524. * UTF-8 before being hashed. A sample implementation of this conversion
  2525. * is in section 8.
  2526. */
  2527. /* add to challenge */
  2528. {
  2529. unsigned resplen = 0;
  2530. if (add_to_challenge(sparams->utils,
  2531. &text->out_buf, &text->out_buf_len, &resplen,
  2532. "rspauth", (unsigned char *) text->response_value,
  2533. text->http_mode ? TRUE : FALSE) != SASL_OK) {
  2534. SETERROR(sparams->utils, "internal error: add_to_challenge failed");
  2535. result = SASL_FAIL;
  2536. goto FreeAllMem;
  2537. }
  2538. if (text->http_mode) {
  2539. /* per RFC 2617 */
  2540. char ncvalue[10];
  2541. if (add_to_challenge(sparams->utils,
  2542. &text->out_buf, &text->out_buf_len, &resplen,
  2543. "cnonce", cnonce, TRUE) != SASL_OK) {
  2544. result = SASL_FAIL;
  2545. goto FreeAllMem;
  2546. }
  2547. snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
  2548. if (add_to_challenge(sparams->utils,
  2549. &text->out_buf, &text->out_buf_len, &resplen,
  2550. "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
  2551. result = SASL_FAIL;
  2552. goto FreeAllMem;
  2553. }
  2554. if (add_to_challenge(sparams->utils,
  2555. &text->out_buf, &text->out_buf_len, &resplen,
  2556. "qop", (unsigned char *) qop, TRUE) != SASL_OK) {
  2557. result = SASL_FAIL;
  2558. goto FreeAllMem;
  2559. }
  2560. }
  2561. /* self check */
  2562. if (strlen(text->out_buf) > 2048) {
  2563. result = SASL_FAIL;
  2564. goto FreeAllMem;
  2565. }
  2566. }
  2567. *serveroutlen = (unsigned) strlen(text->out_buf);
  2568. *serverout = text->out_buf;
  2569. result = SASL_OK;
  2570. FreeAllMem:
  2571. if (clientinlen > 0 &&
  2572. text->reauth->timeout &&
  2573. sparams->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
  2574. /* Look for an entry for the nonce value */
  2575. unsigned val = hash((char *) nonce) % text->reauth->size;
  2576. switch (result) {
  2577. case SASL_OK:
  2578. /* successful auth, setup for future reauth */
  2579. if (text->nonce_count == 1) {
  2580. /* successful initial auth, create new entry */
  2581. clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
  2582. text->reauth->e[val].authid = username; username = NULL;
  2583. text->reauth->e[val].realm = text->realm; text->realm = NULL;
  2584. text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
  2585. text->reauth->e[val].cnonce = cnonce; cnonce = NULL;
  2586. }
  2587. if (text->nonce_count < text->reauth->e[val].nonce_count) {
  2588. /* paranoia. prevent replay attacks */
  2589. clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
  2590. }
  2591. else {
  2592. text->reauth->e[val].nonce_count = ++text->nonce_count;
  2593. text->reauth->e[val].u.s.timestamp = time(0);
  2594. }
  2595. break;
  2596. default:
  2597. if (text->nonce_count > 1) {
  2598. /* failed reauth, clear entry */
  2599. clear_reauth_entry(&text->reauth->e[val], SERVER, sparams->utils);
  2600. }
  2601. else {
  2602. /* failed initial auth, leave existing cache */
  2603. }
  2604. }
  2605. sparams->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
  2606. }
  2607. /* free everything */
  2608. if (in_start) sparams->utils->free (in_start);
  2609. if (full_username != NULL)
  2610. sparams->utils->free (full_username);
  2611. if (username != NULL)
  2612. sparams->utils->free (username);
  2613. if (authorization_id != NULL)
  2614. sparams->utils->free (authorization_id);
  2615. if (realm != NULL)
  2616. sparams->utils->free (realm);
  2617. if (nonce != NULL)
  2618. sparams->utils->free (nonce);
  2619. if (cnonce != NULL)
  2620. sparams->utils->free (cnonce);
  2621. if (response != NULL)
  2622. sparams->utils->free (response);
  2623. if (cipher != NULL)
  2624. sparams->utils->free (cipher);
  2625. if (serverresponse != NULL)
  2626. sparams->utils->free(serverresponse);
  2627. if (charset != NULL)
  2628. sparams->utils->free (charset);
  2629. if (digesturi != NULL)
  2630. sparams->utils->free (digesturi);
  2631. if (qop!=NULL)
  2632. sparams->utils->free (qop);
  2633. if (sec)
  2634. _plug_free_secret(sparams->utils, &sec);
  2635. return result;
  2636. }
  2637. static int digestmd5_server_mech_step(void *conn_context,
  2638. sasl_server_params_t *sparams,
  2639. const char *clientin,
  2640. unsigned clientinlen,
  2641. const char **serverout,
  2642. unsigned *serveroutlen,
  2643. sasl_out_params_t *oparams)
  2644. {
  2645. context_t *text = (context_t *) conn_context;
  2646. server_context_t *stext = (server_context_t *) conn_context;
  2647. *serverout = NULL;
  2648. *serveroutlen = 0;
  2649. if (clientinlen > 4096) return SASL_BADPROT;
  2650. if (text == NULL) {
  2651. return SASL_BADPROT;
  2652. }
  2653. switch (text->state) {
  2654. case 1:
  2655. /* setup SSF limits */
  2656. if (!text->http_mode && /* HTTP Digest doesn't need buffer */
  2657. !sparams->props.maxbufsize) {
  2658. stext->limitssf = 0;
  2659. stext->requiressf = 0;
  2660. } else {
  2661. if (sparams->props.max_ssf < sparams->external_ssf) {
  2662. stext->limitssf = 0;
  2663. } else {
  2664. stext->limitssf =
  2665. sparams->props.max_ssf - sparams->external_ssf;
  2666. }
  2667. if (sparams->props.min_ssf < sparams->external_ssf) {
  2668. stext->requiressf = 0;
  2669. } else {
  2670. stext->requiressf =
  2671. sparams->props.min_ssf - sparams->external_ssf;
  2672. }
  2673. }
  2674. if (clientin && text->reauth->timeout) {
  2675. /* here's where we attempt fast reauth if possible */
  2676. if (digestmd5_server_mech_step2(stext, sparams,
  2677. clientin, clientinlen,
  2678. serverout, serveroutlen,
  2679. oparams) == SASL_OK) {
  2680. return SASL_OK;
  2681. }
  2682. sparams->utils->log(NULL, SASL_LOG_WARN,
  2683. "DIGEST-MD5 reauth failed\n");
  2684. /* re-initialize everything for a fresh start */
  2685. memset(oparams, 0, sizeof(sasl_out_params_t));
  2686. if (text->nonce) sparams->utils->free(text->nonce);
  2687. if (text->realm) sparams->utils->free(text->realm);
  2688. text->realm = NULL;
  2689. text->nonce = NULL;
  2690. /* fall through and issue challenge */
  2691. }
  2692. return digestmd5_server_mech_step1(stext, sparams,
  2693. clientin, clientinlen,
  2694. serverout, serveroutlen, oparams);
  2695. case 2:
  2696. return digestmd5_server_mech_step2(stext, sparams,
  2697. clientin, clientinlen,
  2698. serverout, serveroutlen, oparams);
  2699. default:
  2700. sparams->utils->log(NULL, SASL_LOG_ERR,
  2701. "Invalid DIGEST-MD5 server step %d\n", text->state);
  2702. return SASL_FAIL;
  2703. }
  2704. return SASL_FAIL; /* should never get here */
  2705. }
  2706. static void digestmd5_server_mech_dispose(void *conn_context,
  2707. const sasl_utils_t *utils)
  2708. {
  2709. server_context_t *stext = (server_context_t *) conn_context;
  2710. if (!stext || !utils) return;
  2711. digestmd5_common_mech_dispose(conn_context, utils);
  2712. }
  2713. static sasl_server_plug_t digestmd5_server_plugins[] =
  2714. {
  2715. {
  2716. "DIGEST-MD5", /* mech_name */
  2717. #ifdef WITH_RC4
  2718. 128, /* max_ssf */
  2719. #elif defined(WITH_DES)
  2720. 112,
  2721. #else
  2722. 1,
  2723. #endif
  2724. SASL_SEC_NOPLAINTEXT
  2725. | SASL_SEC_NOANONYMOUS
  2726. | SASL_SEC_MUTUAL_AUTH, /* security_flags */
  2727. SASL_FEAT_ALLOWS_PROXY
  2728. | SASL_FEAT_SUPPORTS_HTTP, /* features */
  2729. &server_glob_context, /* glob_context */
  2730. &digestmd5_server_mech_new, /* mech_new */
  2731. &digestmd5_server_mech_step, /* mech_step */
  2732. &digestmd5_server_mech_dispose, /* mech_dispose */
  2733. &digestmd5_common_mech_free, /* mech_free */
  2734. NULL, /* setpass */
  2735. NULL, /* user_query */
  2736. NULL, /* idle */
  2737. NULL, /* mech avail */
  2738. NULL /* spare */
  2739. }
  2740. };
  2741. int digestmd5_server_plug_init(sasl_utils_t *utils,
  2742. int maxversion,
  2743. int *out_version,
  2744. sasl_server_plug_t **pluglist,
  2745. int *plugcount)
  2746. {
  2747. reauth_cache_t *reauth_cache;
  2748. const char *timeout = NULL;
  2749. unsigned int len;
  2750. if (maxversion < SASL_SERVER_PLUG_VERSION) {
  2751. return SASL_BADVERS;
  2752. }
  2753. /* reauth cache */
  2754. reauth_cache = utils->malloc(sizeof(reauth_cache_t));
  2755. if (reauth_cache == NULL) {
  2756. return SASL_NOMEM;
  2757. }
  2758. memset(reauth_cache, 0, sizeof(reauth_cache_t));
  2759. reauth_cache->i_am = SERVER;
  2760. /* fetch and canonify the reauth_timeout */
  2761. utils->getopt(utils->getopt_context, "DIGEST-MD5", "reauth_timeout",
  2762. &timeout, &len);
  2763. if (timeout) {
  2764. reauth_cache->timeout = (time_t) 60 * strtol(timeout, NULL, 10);
  2765. }
  2766. if (reauth_cache->timeout < 0) {
  2767. reauth_cache->timeout = 0;
  2768. }
  2769. if (reauth_cache->timeout) {
  2770. /* mutex */
  2771. reauth_cache->mutex = utils->mutex_alloc();
  2772. if (!reauth_cache->mutex) {
  2773. utils->free(reauth_cache);
  2774. return SASL_FAIL;
  2775. }
  2776. /* entries */
  2777. reauth_cache->size = 100;
  2778. reauth_cache->e = utils->malloc(reauth_cache->size *
  2779. sizeof(reauth_entry_t));
  2780. if (reauth_cache->e == NULL) {
  2781. utils->mutex_free(reauth_cache->mutex);
  2782. utils->free(reauth_cache);
  2783. return SASL_NOMEM;
  2784. }
  2785. memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
  2786. }
  2787. ((digest_glob_context_t *) digestmd5_server_plugins[0].glob_context)->reauth = reauth_cache;
  2788. *out_version = SASL_SERVER_PLUG_VERSION;
  2789. *pluglist = digestmd5_server_plugins;
  2790. *plugcount = 1;
  2791. return SASL_OK;
  2792. }
  2793. /***************************** Client Section *****************************/
  2794. typedef struct client_context {
  2795. context_t common;
  2796. sasl_secret_t *password; /* user password */
  2797. unsigned int free_password; /* set if we need to free password */
  2798. int protection;
  2799. struct digest_cipher *cipher;
  2800. unsigned long server_maxbuf;
  2801. /* for HTTP mode (RFC 2617) only */
  2802. char *algorithm;
  2803. unsigned char *opaque;
  2804. } client_context_t;
  2805. static digest_glob_context_t client_glob_context;
  2806. /* calculate H(A1) as per spec */
  2807. static void DigestCalcHA1(context_t * text,
  2808. const sasl_utils_t * utils,
  2809. char *pszAlg,
  2810. unsigned char *pszUserName,
  2811. unsigned char *pszRealm,
  2812. sasl_secret_t * pszPassword,
  2813. unsigned char *pszAuthorization_id,
  2814. unsigned char *pszNonce,
  2815. unsigned char *pszCNonce,
  2816. HASHHEX SessionKey)
  2817. {
  2818. MD5_CTX Md5Ctx;
  2819. HASH HA1;
  2820. DigestCalcSecret(utils,
  2821. pszUserName,
  2822. pszRealm,
  2823. (unsigned char *) pszPassword->data,
  2824. pszPassword->len,
  2825. FALSE,
  2826. HA1);
  2827. if (!text->http_mode || /* per RFC 2831 */
  2828. (pszAlg && strcasecmp(pszAlg, "md5-sess") == 0)) { /* per RFC 2617 */
  2829. /* calculate the session key */
  2830. utils->MD5Init(&Md5Ctx);
  2831. if (text->http_mode) {
  2832. /* per RFC 2617 Errata ID 1649 */
  2833. HASHHEX HA1Hex;
  2834. CvtHex(HA1, HA1Hex);
  2835. utils->MD5Update(&Md5Ctx, HA1Hex, HASHHEXLEN);
  2836. }
  2837. else {
  2838. /* per RFC 2831 */
  2839. utils->MD5Update(&Md5Ctx, HA1, HASHLEN);
  2840. }
  2841. utils->MD5Update(&Md5Ctx, COLON, 1);
  2842. utils->MD5Update(&Md5Ctx, pszNonce, (unsigned) strlen((char *) pszNonce));
  2843. utils->MD5Update(&Md5Ctx, COLON, 1);
  2844. utils->MD5Update(&Md5Ctx, pszCNonce, (unsigned) strlen((char *) pszCNonce));
  2845. if (pszAuthorization_id != NULL) {
  2846. utils->MD5Update(&Md5Ctx, COLON, 1);
  2847. utils->MD5Update(&Md5Ctx, pszAuthorization_id,
  2848. (unsigned) strlen((char *) pszAuthorization_id));
  2849. }
  2850. utils->MD5Final(HA1, &Md5Ctx);
  2851. }
  2852. CvtHex(HA1, SessionKey);
  2853. /* xxx rc-* use different n */
  2854. /* save HA1 because we'll need it for the privacy and integrity keys */
  2855. memcpy(text->HA1, HA1, sizeof(HASH));
  2856. }
  2857. static char *calculate_response(context_t * text,
  2858. const sasl_utils_t * utils,
  2859. char *algorithm,
  2860. unsigned char *username,
  2861. unsigned char *realm,
  2862. unsigned char *nonce,
  2863. unsigned int ncvalue,
  2864. unsigned char *cnonce,
  2865. char *qop,
  2866. const sasl_http_request_t *request,
  2867. sasl_secret_t * passwd,
  2868. unsigned char *authorization_id,
  2869. char **response_value)
  2870. {
  2871. HASHHEX SessionKey;
  2872. HASH EntityHash;
  2873. HASHHEX HEntity;
  2874. HASHHEX Response;
  2875. char *result;
  2876. /* Verifing that all parameters was defined */
  2877. if(!username || !cnonce || !nonce || !ncvalue || !request || !passwd) {
  2878. PARAMERROR( utils );
  2879. return NULL;
  2880. }
  2881. if (realm == NULL) {
  2882. /* a NULL realm is equivalent to the empty string */
  2883. realm = (unsigned char *) "";
  2884. }
  2885. if (qop == NULL) {
  2886. /* default to a qop of just authentication */
  2887. qop = "auth";
  2888. }
  2889. DigestCalcHA1(text,
  2890. utils,
  2891. algorithm,
  2892. username,
  2893. realm,
  2894. passwd,
  2895. authorization_id,
  2896. nonce,
  2897. cnonce,
  2898. SessionKey);
  2899. if (text->http_mode) {
  2900. /* per RFC 2617 */
  2901. MD5_CTX Md5Ctx;
  2902. utils->MD5Init(&Md5Ctx);
  2903. utils->MD5Update(&Md5Ctx, request->entity, request->elen);
  2904. utils->MD5Final(EntityHash, &Md5Ctx);
  2905. }
  2906. else {
  2907. /* per RFC 2831 */
  2908. memset(EntityHash, 0, HASHLEN);
  2909. }
  2910. CvtHex(EntityHash, HEntity);
  2911. DigestCalcResponse(utils,
  2912. SessionKey,/* HEX(H(A1)) */
  2913. nonce, /* nonce from server */
  2914. ncvalue, /* 8 hex digits */
  2915. cnonce, /* client nonce */
  2916. (unsigned char *) qop, /* qop-value: "", "auth",
  2917. * "auth-int" */
  2918. (unsigned char *) request->uri, /* requested URL */
  2919. (unsigned char *) request->method,
  2920. HEntity, /* H(entity body) if qop="auth-int" */
  2921. Response /* request-digest or response-digest */
  2922. );
  2923. result = utils->malloc(HASHHEXLEN + 1);
  2924. memcpy(result, Response, HASHHEXLEN);
  2925. result[HASHHEXLEN] = 0;
  2926. if (response_value != NULL) {
  2927. char * new_response_value;
  2928. DigestCalcResponse(utils,
  2929. SessionKey, /* HEX(H(A1)) */
  2930. nonce, /* nonce from server */
  2931. ncvalue, /* 8 hex digits */
  2932. cnonce, /* client nonce */
  2933. (unsigned char *) qop, /* qop-value: "", "auth",
  2934. * "auth-int" */
  2935. (unsigned char *) request->uri, /* requested URL */
  2936. NULL,
  2937. HEntity, /* H(entity body) if qop="auth-int" */
  2938. Response /* request-digest or response-digest */
  2939. );
  2940. new_response_value = utils->realloc(*response_value, HASHHEXLEN + 1);
  2941. if (new_response_value == NULL) {
  2942. free (*response_value);
  2943. *response_value = NULL;
  2944. return NULL;
  2945. }
  2946. *response_value = new_response_value;
  2947. memcpy(*response_value, Response, HASHHEXLEN);
  2948. (*response_value)[HASHHEXLEN] = 0;
  2949. }
  2950. return result;
  2951. }
  2952. static int make_client_response(context_t *text,
  2953. sasl_client_params_t *params,
  2954. sasl_out_params_t *oparams)
  2955. {
  2956. client_context_t *ctext = (client_context_t *) text;
  2957. char *qop = NULL;
  2958. unsigned nbits = 0;
  2959. char *digesturi = NULL;
  2960. bool IsUTF8 = FALSE;
  2961. char ncvalue[10];
  2962. char maxbufstr[64];
  2963. char *response = NULL;
  2964. unsigned resplen = 0;
  2965. int result = SASL_OK;
  2966. cipher_free_t *old_cipher_free = NULL;
  2967. sasl_http_request_t rfc2831_request;
  2968. const sasl_http_request_t *request;
  2969. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  2970. "DIGEST-MD5 make_client_response()");
  2971. if (oparams->mech_ssf > 1) {
  2972. /* Remember the old cipher free function (if any).
  2973. It will be called later, once we are absolutely
  2974. sure that authentication was successful. */
  2975. old_cipher_free = text->cipher_free;
  2976. /* free the old cipher context first */
  2977. }
  2978. switch (ctext->protection) {
  2979. case DIGEST_PRIVACY:
  2980. qop = "auth-conf";
  2981. oparams->encode = &digestmd5_encode;
  2982. oparams->decode = &digestmd5_decode;
  2983. oparams->mech_ssf = ctext->cipher->ssf;
  2984. nbits = ctext->cipher->n;
  2985. text->cipher_enc = ctext->cipher->cipher_enc;
  2986. text->cipher_dec = ctext->cipher->cipher_dec;
  2987. text->cipher_free = ctext->cipher->cipher_free;
  2988. text->cipher_init = ctext->cipher->cipher_init;
  2989. break;
  2990. case DIGEST_INTEGRITY:
  2991. qop = "auth-int";
  2992. oparams->encode = &digestmd5_encode;
  2993. oparams->decode = &digestmd5_decode;
  2994. oparams->mech_ssf = 1;
  2995. break;
  2996. case DIGEST_NOLAYER:
  2997. default:
  2998. qop = "auth";
  2999. oparams->encode = NULL;
  3000. oparams->decode = NULL;
  3001. oparams->mech_ssf = 0;
  3002. }
  3003. if (text->http_mode) {
  3004. /* per RFC 2617 (HTTP Request as set by calling application) */
  3005. request = params->http_request;
  3006. }
  3007. else {
  3008. /* per RFC 2831 */
  3009. digesturi = params->utils->malloc(strlen(params->service) + 1 +
  3010. strlen(params->serverFQDN) + 1 +
  3011. 1);
  3012. if (digesturi == NULL) {
  3013. result = SASL_NOMEM;
  3014. goto FreeAllocatedMem;
  3015. }
  3016. /* allocated exactly this. safe */
  3017. strcpy(digesturi, params->service);
  3018. strcat(digesturi, "/");
  3019. strcat(digesturi, params->serverFQDN);
  3020. /*
  3021. * strcat (digesturi, "/"); strcat (digesturi, params->serverFQDN);
  3022. */
  3023. rfc2831_request.method = "AUTHENTICATE";
  3024. rfc2831_request.uri = digesturi;
  3025. rfc2831_request.entity = NULL;
  3026. rfc2831_request.elen = 0;
  3027. rfc2831_request.non_persist = 0;
  3028. request = &rfc2831_request;
  3029. }
  3030. /* response */
  3031. response =
  3032. calculate_response(text,
  3033. params->utils,
  3034. ctext->algorithm,
  3035. (unsigned char *) oparams->authid,
  3036. (unsigned char *) text->realm,
  3037. text->nonce,
  3038. text->nonce_count,
  3039. text->cnonce,
  3040. qop,
  3041. request,
  3042. ctext->password,
  3043. strcmp(oparams->user, oparams->authid) ?
  3044. (unsigned char *) oparams->user : NULL,
  3045. &text->response_value);
  3046. resplen = 0;
  3047. if (text->out_buf) params->utils->free(text->out_buf);
  3048. text->out_buf = NULL;
  3049. text->out_buf_len = 0;
  3050. if (add_to_challenge(params->utils,
  3051. &text->out_buf, &text->out_buf_len, &resplen,
  3052. "username", (unsigned char *) oparams->authid,
  3053. TRUE) != SASL_OK) {
  3054. result = SASL_FAIL;
  3055. goto FreeAllocatedMem;
  3056. }
  3057. if (add_to_challenge(params->utils,
  3058. &text->out_buf, &text->out_buf_len, &resplen,
  3059. "realm", (unsigned char *) text->realm,
  3060. TRUE) != SASL_OK) {
  3061. result = SASL_FAIL;
  3062. goto FreeAllocatedMem;
  3063. }
  3064. if (strcmp(oparams->user, oparams->authid)) {
  3065. if (add_to_challenge(params->utils,
  3066. &text->out_buf, &text->out_buf_len, &resplen,
  3067. "authzid", (unsigned char *) oparams->user, TRUE) != SASL_OK) {
  3068. result = SASL_FAIL;
  3069. goto FreeAllocatedMem;
  3070. }
  3071. }
  3072. if (add_to_challenge(params->utils,
  3073. &text->out_buf, &text->out_buf_len, &resplen,
  3074. "nonce", text->nonce, TRUE) != SASL_OK) {
  3075. result = SASL_FAIL;
  3076. goto FreeAllocatedMem;
  3077. }
  3078. if (add_to_challenge(params->utils,
  3079. &text->out_buf, &text->out_buf_len, &resplen,
  3080. "cnonce", text->cnonce, TRUE) != SASL_OK) {
  3081. result = SASL_FAIL;
  3082. goto FreeAllocatedMem;
  3083. }
  3084. snprintf(ncvalue, sizeof(ncvalue), "%08x", text->nonce_count);
  3085. if (add_to_challenge(params->utils,
  3086. &text->out_buf, &text->out_buf_len, &resplen,
  3087. "nc", (unsigned char *) ncvalue, FALSE) != SASL_OK) {
  3088. result = SASL_FAIL;
  3089. goto FreeAllocatedMem;
  3090. }
  3091. if (add_to_challenge(params->utils,
  3092. &text->out_buf, &text->out_buf_len, &resplen,
  3093. "qop", (unsigned char *) qop, FALSE) != SASL_OK) {
  3094. result = SASL_FAIL;
  3095. goto FreeAllocatedMem;
  3096. }
  3097. if (ctext->cipher != NULL) {
  3098. if (add_to_challenge(params->utils,
  3099. &text->out_buf, &text->out_buf_len, &resplen,
  3100. "cipher",
  3101. (unsigned char *) ctext->cipher->name,
  3102. FALSE) != SASL_OK) {
  3103. result = SASL_FAIL;
  3104. goto FreeAllocatedMem;
  3105. }
  3106. }
  3107. if (params->props.maxbufsize) {
  3108. snprintf(maxbufstr, sizeof(maxbufstr), "%d", params->props.maxbufsize);
  3109. if (add_to_challenge(params->utils,
  3110. &text->out_buf, &text->out_buf_len, &resplen,
  3111. "maxbuf", (unsigned char *) maxbufstr,
  3112. FALSE) != SASL_OK) {
  3113. SETERROR(params->utils,
  3114. "internal error: add_to_challenge maxbuf failed");
  3115. goto FreeAllocatedMem;
  3116. }
  3117. }
  3118. if (IsUTF8) {
  3119. if (add_to_challenge(params->utils,
  3120. &text->out_buf, &text->out_buf_len, &resplen,
  3121. "charset", (unsigned char *) "utf-8",
  3122. FALSE) != SASL_OK) {
  3123. result = SASL_FAIL;
  3124. goto FreeAllocatedMem;
  3125. }
  3126. }
  3127. if (add_to_challenge(params->utils,
  3128. &text->out_buf, &text->out_buf_len, &resplen,
  3129. text->http_mode ? "uri" /* per RFC 2617 */
  3130. : "digest-uri", /* per RFC 2831 */
  3131. (unsigned char *) request->uri,
  3132. TRUE) != SASL_OK) {
  3133. result = SASL_FAIL;
  3134. goto FreeAllocatedMem;
  3135. }
  3136. if (text->http_mode) {
  3137. /* per RFC 2617: algorithm & opaque MUST be sent back to server */
  3138. if (add_to_challenge(params->utils,
  3139. &text->out_buf, &text->out_buf_len, &resplen,
  3140. "algorithm", (unsigned char *) ctext->algorithm,
  3141. FALSE) != SASL_OK) {
  3142. result = SASL_FAIL;
  3143. goto FreeAllocatedMem;
  3144. }
  3145. if (ctext->opaque) {
  3146. if (add_to_challenge(params->utils,
  3147. &text->out_buf, &text->out_buf_len, &resplen,
  3148. "opaque", ctext->opaque, TRUE) != SASL_OK) {
  3149. result = SASL_FAIL;
  3150. goto FreeAllocatedMem;
  3151. }
  3152. }
  3153. }
  3154. if (add_to_challenge(params->utils,
  3155. &text->out_buf, &text->out_buf_len, &resplen,
  3156. "response", (unsigned char *) response,
  3157. FALSE) != SASL_OK) {
  3158. result = SASL_FAIL;
  3159. goto FreeAllocatedMem;
  3160. }
  3161. /* self check */
  3162. if (strlen(text->out_buf) > 2048) {
  3163. result = SASL_FAIL;
  3164. goto FreeAllocatedMem;
  3165. }
  3166. /* set oparams */
  3167. oparams->maxoutbuf = ctext->server_maxbuf;
  3168. if(oparams->mech_ssf > 1) {
  3169. /* MAC block (privacy) */
  3170. oparams->maxoutbuf -= 25;
  3171. } else if(oparams->mech_ssf == 1) {
  3172. /* MAC block (integrity) */
  3173. oparams->maxoutbuf -= 16;
  3174. }
  3175. text->seqnum = 0; /* for integrity/privacy */
  3176. text->rec_seqnum = 0; /* for integrity/privacy */
  3177. text->utils = params->utils;
  3178. /* Free the old security layer, if any */
  3179. if (old_cipher_free) old_cipher_free(text);
  3180. /* used by layers */
  3181. _plug_decode_init(&text->decode_context, text->utils,
  3182. params->props.maxbufsize ? params->props.maxbufsize :
  3183. DEFAULT_BUFSIZE);
  3184. if (oparams->mech_ssf > 0) {
  3185. unsigned char enckey[16];
  3186. unsigned char deckey[16];
  3187. create_layer_keys(text, params->utils, text->HA1, nbits,
  3188. enckey, deckey);
  3189. /* initialize cipher if need be */
  3190. if (text->cipher_init) {
  3191. text->cipher_init(text, enckey, deckey);
  3192. }
  3193. }
  3194. result = SASL_OK;
  3195. FreeAllocatedMem:
  3196. if (digesturi) params->utils->free(digesturi);
  3197. if (response) params->utils->free(response);
  3198. return result;
  3199. }
  3200. static int parse_server_challenge(client_context_t *ctext,
  3201. sasl_client_params_t *params,
  3202. const char *serverin, unsigned serverinlen,
  3203. char ***outrealms, int *noutrealm)
  3204. {
  3205. context_t *text = (context_t *) ctext;
  3206. int result = SASL_OK;
  3207. char *in_start = NULL;
  3208. char *in = NULL;
  3209. char **realms = NULL;
  3210. int nrealm = 0;
  3211. sasl_ssf_t limit, musthave = 0;
  3212. sasl_ssf_t external;
  3213. int protection = 0;
  3214. int saw_qop = 0;
  3215. int ciphers = 0;
  3216. int maxbuf_count = 0;
  3217. int algorithm_count = 0;
  3218. int opaque_count = 0;
  3219. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3220. "DIGEST-MD5 parse_server_challenge()");
  3221. if (!serverin || !serverinlen) {
  3222. params->utils->seterror(params->utils->conn, 0,
  3223. "no server challenge");
  3224. return SASL_FAIL;
  3225. }
  3226. in_start = in = params->utils->malloc(serverinlen + 1);
  3227. if (in == NULL) return SASL_NOMEM;
  3228. memcpy(in, serverin, serverinlen);
  3229. in[serverinlen] = 0;
  3230. ctext->server_maxbuf = 65536; /* Default value for maxbuf */
  3231. /* create a new cnonce */
  3232. text->cnonce = create_nonce(params->utils);
  3233. if (text->cnonce == NULL) {
  3234. params->utils->seterror(params->utils->conn, 0,
  3235. "failed to create cnonce");
  3236. result = SASL_FAIL;
  3237. goto FreeAllocatedMem;
  3238. }
  3239. /* parse the challenge */
  3240. while (in[0] != '\0') {
  3241. char *name, *value;
  3242. get_pair(&in, &name, &value);
  3243. /* if parse error */
  3244. if (name == NULL) {
  3245. params->utils->seterror(params->utils->conn, 0, "Parse error");
  3246. result = SASL_BADAUTH;
  3247. goto FreeAllocatedMem;
  3248. }
  3249. if (*name == '\0') {
  3250. break;
  3251. }
  3252. if (strcasecmp(name, "realm") == 0) {
  3253. nrealm++;
  3254. if(!realms)
  3255. realms = params->utils->malloc(sizeof(char *) * (nrealm + 1));
  3256. else
  3257. realms = params->utils->realloc(realms,
  3258. sizeof(char *) * (nrealm + 1));
  3259. if (realms == NULL) {
  3260. result = SASL_NOMEM;
  3261. goto FreeAllocatedMem;
  3262. }
  3263. _plug_strdup(params->utils, value, &realms[nrealm-1], NULL);
  3264. realms[nrealm] = NULL;
  3265. } else if (strcasecmp(name, "nonce") == 0) {
  3266. _plug_strdup(params->utils, value, (char **) &text->nonce,
  3267. NULL);
  3268. text->nonce_count = 1;
  3269. } else if (strcasecmp(name, "qop") == 0) {
  3270. saw_qop = 1;
  3271. while (value && *value) {
  3272. char *comma;
  3273. char *end_val;
  3274. SKIP_SPACES_IN_QOP:
  3275. /* skipping spaces: */
  3276. value = skip_lws(value);
  3277. if (*value == '\0') {
  3278. break;
  3279. }
  3280. /* check for an extreme case when there is no data: LWSP ',' */
  3281. if (*value == ',') {
  3282. value++;
  3283. goto SKIP_SPACES_IN_QOP;
  3284. }
  3285. comma = strchr(value, ',');
  3286. if (comma != NULL) {
  3287. *comma++ = '\0';
  3288. }
  3289. /* skip LWSP at the end of the value (if any), skip_r_lws returns pointer to
  3290. the first LWSP character, NUL (if there were none) or NULL if the value
  3291. is entirely from LWSP characters */
  3292. end_val = skip_r_lws (value);
  3293. if (end_val == NULL) {
  3294. value = comma;
  3295. continue;
  3296. } else {
  3297. /* strip LWSP */
  3298. *end_val = '\0';
  3299. }
  3300. if (strcasecmp(value, "auth-conf") == 0) {
  3301. protection |= DIGEST_PRIVACY;
  3302. } else if (strcasecmp(value, "auth-int") == 0) {
  3303. protection |= DIGEST_INTEGRITY;
  3304. } else if (strcasecmp(value, "auth") == 0) {
  3305. protection |= DIGEST_NOLAYER;
  3306. } else {
  3307. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3308. "Server supports unknown layer: %s\n",
  3309. value);
  3310. }
  3311. value = comma;
  3312. }
  3313. } else if (strcasecmp(name, "cipher") == 0) {
  3314. while (value && *value) {
  3315. struct digest_cipher *cipher = available_ciphers;
  3316. char *comma;
  3317. char *end_val;
  3318. SKIP_SPACES_IN_CIPHER:
  3319. /* skipping spaces: */
  3320. value = skip_lws(value);
  3321. if (*value == '\0') {
  3322. break;
  3323. }
  3324. /* check for an extreme case when there is no data: LWSP ',' */
  3325. if (*value == ',') {
  3326. value++;
  3327. goto SKIP_SPACES_IN_CIPHER;
  3328. }
  3329. comma = strchr(value, ',');
  3330. if (comma != NULL) {
  3331. *comma++ = '\0';
  3332. }
  3333. /* skip LWSP at the end of the value, skip_r_lws returns pointer to
  3334. the first LWSP character or NULL */
  3335. end_val = skip_r_lws (value);
  3336. if (end_val == NULL) {
  3337. value = comma;
  3338. continue;
  3339. } else {
  3340. /* strip LWSP */
  3341. *end_val = '\0';
  3342. }
  3343. /* do we support this cipher? */
  3344. while (cipher->name) {
  3345. if (!strcasecmp(value, cipher->name)) break;
  3346. cipher++;
  3347. }
  3348. if (cipher->name) {
  3349. ciphers |= cipher->flag;
  3350. } else {
  3351. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3352. "Server supports unknown cipher: %s\n",
  3353. value);
  3354. }
  3355. value = comma;
  3356. }
  3357. } else if (strcasecmp(name, "stale") == 0 && ctext->password) {
  3358. /* clear any cached password */
  3359. if (ctext->free_password)
  3360. _plug_free_secret(params->utils, &ctext->password);
  3361. ctext->password = NULL;
  3362. } else if (strcasecmp(name, "maxbuf") == 0) {
  3363. /* maxbuf A number indicating the size of the largest
  3364. * buffer the server is able to receive when using
  3365. * "auth-int". If this directive is missing, the default
  3366. * value is 65536. This directive may appear at most once;
  3367. * if multiple instances are present, the client should
  3368. * abort the authentication exchange.
  3369. */
  3370. maxbuf_count++;
  3371. if (maxbuf_count != 1) {
  3372. result = SASL_BADAUTH;
  3373. params->utils->seterror(params->utils->conn, 0,
  3374. "At least two maxbuf directives found. Authentication aborted");
  3375. goto FreeAllocatedMem;
  3376. }
  3377. if (str2ul32 (value, &ctext->server_maxbuf) == FALSE) {
  3378. result = SASL_BADAUTH;
  3379. params->utils->seterror(params->utils->conn, 0,
  3380. "Invalid maxbuf parameter received from server (%s)", value);
  3381. goto FreeAllocatedMem;
  3382. }
  3383. if (ctext->server_maxbuf <= 16) {
  3384. result = SASL_BADAUTH;
  3385. params->utils->seterror(params->utils->conn, 0,
  3386. "Invalid maxbuf parameter received from server (too small: %s)", value);
  3387. goto FreeAllocatedMem;
  3388. }
  3389. if (ctext->server_maxbuf > MAX_SASL_BUFSIZE) {
  3390. result = SASL_BADAUTH;
  3391. params->utils->seterror(params->utils->conn, 0,
  3392. "Invalid maxbuf parameter received from server (too big: %s)", value);
  3393. goto FreeAllocatedMem;
  3394. }
  3395. } else if (strcasecmp(name, "charset") == 0) {
  3396. if (strcasecmp(value, "utf-8") != 0) {
  3397. result = SASL_BADAUTH;
  3398. params->utils->seterror(params->utils->conn, 0,
  3399. "Charset must be UTF-8");
  3400. goto FreeAllocatedMem;
  3401. }
  3402. } else if (strcasecmp(name,"algorithm")==0) {
  3403. if (text->http_mode && strcasecmp(value, "md5") == 0) {
  3404. /* per RFC 2617: need to support both "md5" and "md5-sess" */
  3405. }
  3406. else if (strcasecmp(value, "md5-sess") != 0)
  3407. {
  3408. params->utils->seterror(params->utils->conn, 0,
  3409. "'algorithm' isn't 'md5-sess'");
  3410. result = SASL_FAIL;
  3411. goto FreeAllocatedMem;
  3412. }
  3413. if (text->http_mode) {
  3414. /* per RFC 2617: algorithm MUST be saved */
  3415. _plug_strdup(params->utils, value, (char **) &ctext->algorithm,
  3416. NULL);
  3417. }
  3418. algorithm_count++;
  3419. if (algorithm_count > 1)
  3420. {
  3421. params->utils->seterror(params->utils->conn, 0,
  3422. "Must see 'algorithm' only once");
  3423. result = SASL_FAIL;
  3424. goto FreeAllocatedMem;
  3425. }
  3426. } else if (strcasecmp(name,"opaque")==0) {
  3427. /* per RFC 2831: opaque MUST be ignored if received */
  3428. if (text->http_mode) {
  3429. /* per RFC 2617: opaque MUST be saved */
  3430. _plug_strdup(params->utils, value, (char **) &ctext->opaque,
  3431. NULL);
  3432. opaque_count++;
  3433. if (opaque_count > 1)
  3434. {
  3435. params->utils->seterror(params->utils->conn, 0,
  3436. "Must see 'opaque' only once");
  3437. result = SASL_FAIL;
  3438. goto FreeAllocatedMem;
  3439. }
  3440. }
  3441. } else {
  3442. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3443. "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
  3444. name, value);
  3445. }
  3446. }
  3447. if (protection == 0) {
  3448. /* From RFC 2831[bis]:
  3449. This directive is optional; if not present it defaults to "auth". */
  3450. if (saw_qop == 0) {
  3451. protection = DIGEST_NOLAYER;
  3452. } else {
  3453. result = SASL_BADAUTH;
  3454. params->utils->seterror(params->utils->conn, 0,
  3455. "Server doesn't support any known qop level");
  3456. goto FreeAllocatedMem;
  3457. }
  3458. }
  3459. if (algorithm_count != 1) {
  3460. params->utils->seterror(params->utils->conn, 0,
  3461. "Must see 'algorithm' once. Didn't see at all");
  3462. result = SASL_FAIL;
  3463. goto FreeAllocatedMem;
  3464. }
  3465. /* make sure we have everything we require */
  3466. if (text->nonce == NULL) {
  3467. params->utils->seterror(params->utils->conn, 0,
  3468. "Don't have nonce.");
  3469. result = SASL_FAIL;
  3470. goto FreeAllocatedMem;
  3471. }
  3472. /* get requested ssf */
  3473. external = params->external_ssf;
  3474. /* what do we _need_? how much is too much? */
  3475. if (!text->http_mode && /* HTTP Digest doesn't need buffer */
  3476. params->props.maxbufsize == 0) {
  3477. musthave = 0;
  3478. limit = 0;
  3479. } else {
  3480. if (params->props.max_ssf > external) {
  3481. limit = params->props.max_ssf - external;
  3482. } else {
  3483. limit = 0;
  3484. }
  3485. if (params->props.min_ssf > external) {
  3486. musthave = params->props.min_ssf - external;
  3487. } else {
  3488. musthave = 0;
  3489. }
  3490. }
  3491. /* we now go searching for an option that gives us at least "musthave"
  3492. and at most "limit" bits of ssf. */
  3493. if ((limit > 1) && (protection & DIGEST_PRIVACY)) {
  3494. struct digest_cipher *cipher;
  3495. /* let's find an encryption scheme that we like */
  3496. cipher = available_ciphers;
  3497. while (cipher->name) {
  3498. /* examine each cipher we support, see if it meets our security
  3499. requirements, and see if the server supports it.
  3500. choose the best one of these */
  3501. if ((limit >= cipher->ssf) && (musthave <= cipher->ssf) &&
  3502. (ciphers & cipher->flag) &&
  3503. (!ctext->cipher || (cipher->ssf > ctext->cipher->ssf))) {
  3504. ctext->cipher = cipher;
  3505. }
  3506. cipher++;
  3507. }
  3508. if (ctext->cipher) {
  3509. /* we found a cipher we like */
  3510. ctext->protection = DIGEST_PRIVACY;
  3511. } else {
  3512. /* we didn't find any ciphers we like */
  3513. params->utils->seterror(params->utils->conn, 0,
  3514. "No good privacy layers");
  3515. }
  3516. }
  3517. if (ctext->cipher == NULL) {
  3518. /* we failed to find an encryption layer we liked;
  3519. can we use integrity or nothing? */
  3520. if ((limit >= 1) && (musthave <= 1)
  3521. && (protection & DIGEST_INTEGRITY)) {
  3522. /* integrity */
  3523. ctext->protection = DIGEST_INTEGRITY;
  3524. } else if (musthave <= 0) {
  3525. /* no layer */
  3526. ctext->protection = DIGEST_NOLAYER;
  3527. /* See if server supports not having a layer */
  3528. if ((protection & DIGEST_NOLAYER) != DIGEST_NOLAYER) {
  3529. params->utils->seterror(params->utils->conn, 0,
  3530. "Server doesn't support \"no layer\"");
  3531. result = SASL_FAIL;
  3532. goto FreeAllocatedMem;
  3533. }
  3534. } else {
  3535. params->utils->seterror(params->utils->conn, 0,
  3536. "Can't find an acceptable layer");
  3537. result = SASL_TOOWEAK;
  3538. goto FreeAllocatedMem;
  3539. }
  3540. }
  3541. *outrealms = realms;
  3542. *noutrealm = nrealm;
  3543. FreeAllocatedMem:
  3544. if (in_start) params->utils->free(in_start);
  3545. if (result != SASL_OK && realms) {
  3546. int lup;
  3547. /* need to free all the realms */
  3548. for (lup = 0;lup < nrealm; lup++)
  3549. params->utils->free(realms[lup]);
  3550. params->utils->free(realms);
  3551. }
  3552. return result;
  3553. }
  3554. static int ask_user_info(client_context_t *ctext,
  3555. sasl_client_params_t *params,
  3556. char **realms, int nrealm,
  3557. sasl_interact_t **prompt_need,
  3558. sasl_out_params_t *oparams)
  3559. {
  3560. context_t *text = (context_t *) ctext;
  3561. int result = SASL_OK;
  3562. const char *authid = NULL, *userid = NULL, *realm = NULL;
  3563. char *realm_chal = NULL;
  3564. int user_result = SASL_OK;
  3565. int auth_result = SASL_OK;
  3566. int pass_result = SASL_OK;
  3567. int realm_result = SASL_FAIL;
  3568. int i;
  3569. size_t len;
  3570. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3571. "DIGEST-MD5 ask_user_info()");
  3572. /* try to get the authid */
  3573. if (oparams->authid == NULL) {
  3574. auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
  3575. if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT)) {
  3576. return auth_result;
  3577. }
  3578. }
  3579. /* try to get the userid */
  3580. if (oparams->user == NULL) {
  3581. user_result = _plug_get_userid(params->utils, &userid, prompt_need);
  3582. if ((user_result != SASL_OK) && (user_result != SASL_INTERACT)) {
  3583. return user_result;
  3584. }
  3585. }
  3586. /* try to get the password */
  3587. if (ctext->password == NULL) {
  3588. pass_result = _plug_get_password(params->utils, &ctext->password,
  3589. &ctext->free_password, prompt_need);
  3590. if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT)) {
  3591. return pass_result;
  3592. }
  3593. }
  3594. /* try to get the realm */
  3595. if (text->realm == NULL) {
  3596. if (realms) {
  3597. if(nrealm == 1) {
  3598. /* only one choice */
  3599. realm = realms[0];
  3600. realm_result = SASL_OK;
  3601. } else {
  3602. /* ask the user */
  3603. realm_result = _plug_get_realm(params->utils,
  3604. (const char **) realms,
  3605. (const char **) &realm,
  3606. prompt_need);
  3607. }
  3608. }
  3609. /* fake the realm if we must */
  3610. if ((realm_result != SASL_OK) && (realm_result != SASL_INTERACT)) {
  3611. if (params->serverFQDN) {
  3612. realm = params->serverFQDN;
  3613. } else {
  3614. return realm_result;
  3615. }
  3616. }
  3617. }
  3618. /* free prompts we got */
  3619. if (prompt_need && *prompt_need) {
  3620. params->utils->free(*prompt_need);
  3621. *prompt_need = NULL;
  3622. }
  3623. /* if there are prompts not filled in */
  3624. if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
  3625. (pass_result == SASL_INTERACT) || (realm_result == SASL_INTERACT)) {
  3626. /* make our default realm */
  3627. if (realm_result == SASL_INTERACT) {
  3628. if (realms) {
  3629. len = strlen(REALM_CHAL_PREFIX);
  3630. for (i = 0; i < nrealm; i++) {
  3631. len += strlen(realms[i]) + 4 /* " {}," */;
  3632. }
  3633. realm_chal = params->utils->malloc(len + 1);
  3634. strcpy (realm_chal, REALM_CHAL_PREFIX);
  3635. for (i = 0; i < nrealm; i++) {
  3636. strcat (realm_chal, " {");
  3637. strcat (realm_chal, realms[i]);
  3638. strcat (realm_chal, "},");
  3639. }
  3640. /* Replace the terminating comma with dot */
  3641. realm_chal[len-1] = '.';
  3642. } else if (params->serverFQDN) {
  3643. realm_chal = params->utils->malloc(3+strlen(params->serverFQDN));
  3644. if (realm_chal) {
  3645. sprintf(realm_chal, "{%s}", params->serverFQDN);
  3646. } else {
  3647. return SASL_NOMEM;
  3648. }
  3649. }
  3650. }
  3651. /* make the prompt list */
  3652. result =
  3653. _plug_make_prompts(params->utils, prompt_need,
  3654. user_result == SASL_INTERACT ?
  3655. "Please enter your authorization name" : NULL,
  3656. NULL,
  3657. auth_result == SASL_INTERACT ?
  3658. "Please enter your authentication name" : NULL,
  3659. NULL,
  3660. pass_result == SASL_INTERACT ?
  3661. "Please enter your password" : NULL, NULL,
  3662. NULL, NULL, NULL,
  3663. realm_chal ? realm_chal : "{}",
  3664. realm_result == SASL_INTERACT ?
  3665. "Please enter your realm" : NULL,
  3666. params->serverFQDN ? params->serverFQDN : NULL);
  3667. if (result == SASL_OK) return SASL_INTERACT;
  3668. return result;
  3669. }
  3670. if (oparams->authid == NULL) {
  3671. if (!userid || !*userid) {
  3672. result = params->canon_user(params->utils->conn, authid, 0,
  3673. SASL_CU_AUTHID | SASL_CU_AUTHZID,
  3674. oparams);
  3675. }
  3676. else {
  3677. result = params->canon_user(params->utils->conn,
  3678. authid, 0, SASL_CU_AUTHID, oparams);
  3679. if (result != SASL_OK) return result;
  3680. result = params->canon_user(params->utils->conn,
  3681. userid, 0, SASL_CU_AUTHZID, oparams);
  3682. }
  3683. if (result != SASL_OK) return result;
  3684. }
  3685. /* Get an allocated version of the realm into the structure */
  3686. if (realm && text->realm == NULL) {
  3687. _plug_strdup(params->utils, realm, (char **) &text->realm, NULL);
  3688. }
  3689. return result;
  3690. }
  3691. static int digestmd5_client_mech_new(void *glob_context,
  3692. sasl_client_params_t * params,
  3693. void **conn_context)
  3694. {
  3695. context_t *text;
  3696. if ((params->flags & SASL_NEED_HTTP) && !params->http_request) {
  3697. SETERROR(params->utils,
  3698. "DIGEST-MD5 unavailable due to lack of HTTP request");
  3699. return SASL_BADPARAM;
  3700. }
  3701. /* holds state are in -- allocate client size */
  3702. text = params->utils->malloc(sizeof(client_context_t));
  3703. if (text == NULL)
  3704. return SASL_NOMEM;
  3705. memset((client_context_t *)text, 0, sizeof(client_context_t));
  3706. text->state = 1;
  3707. text->i_am = CLIENT;
  3708. text->http_mode = (params->flags & SASL_NEED_HTTP);
  3709. text->reauth = ((digest_glob_context_t *) glob_context)->reauth;
  3710. *conn_context = text;
  3711. return SASL_OK;
  3712. }
  3713. static int
  3714. digestmd5_client_mech_step1(client_context_t *ctext,
  3715. sasl_client_params_t *params,
  3716. const char *serverin __attribute__((unused)),
  3717. unsigned serverinlen __attribute__((unused)),
  3718. sasl_interact_t **prompt_need,
  3719. const char **clientout,
  3720. unsigned *clientoutlen,
  3721. sasl_out_params_t *oparams)
  3722. {
  3723. context_t *text = (context_t *) ctext;
  3724. int result = SASL_FAIL;
  3725. unsigned val;
  3726. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3727. "DIGEST-MD5 client step 1");
  3728. result = ask_user_info(ctext, params, NULL, 0, prompt_need, oparams);
  3729. if (result != SASL_OK) return result;
  3730. /* check if we have cached info for this user on this server */
  3731. val = hash(params->serverFQDN) % text->reauth->size;
  3732. if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
  3733. if (text->reauth->e[val].u.c.serverFQDN &&
  3734. !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
  3735. params->serverFQDN) &&
  3736. !strcmp(text->reauth->e[val].authid, oparams->authid)) {
  3737. /* we have info, so use it */
  3738. if (text->realm) params->utils->free(text->realm);
  3739. _plug_strdup(params->utils, text->reauth->e[val].realm,
  3740. &text->realm, NULL);
  3741. _plug_strdup(params->utils, (char *) text->reauth->e[val].nonce,
  3742. (char **) &text->nonce, NULL);
  3743. text->nonce_count = ++text->reauth->e[val].nonce_count;
  3744. _plug_strdup(params->utils, (char *) text->reauth->e[val].cnonce,
  3745. (char **) &text->cnonce, NULL);
  3746. if (text->http_mode) {
  3747. /* per RFC 2617: algorithm & opaque MUST be sent back to server */
  3748. _plug_strdup(params->utils,
  3749. (char *) text->reauth->e[val].u.c.algorithm,
  3750. (char **) &ctext->algorithm, NULL);
  3751. if (text->reauth->e[val].u.c.opaque) {
  3752. _plug_strdup(params->utils,
  3753. (char *) text->reauth->e[val].u.c.opaque,
  3754. (char **) &ctext->opaque, NULL);
  3755. }
  3756. }
  3757. ctext->protection = text->reauth->e[val].u.c.protection;
  3758. ctext->cipher = text->reauth->e[val].u.c.cipher;
  3759. ctext->server_maxbuf = text->reauth->e[val].u.c.server_maxbuf;
  3760. }
  3761. params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
  3762. }
  3763. if (!text->nonce) {
  3764. /* we don't have any reauth info, so just return
  3765. * that there is no initial client send */
  3766. text->state = 2;
  3767. return SASL_CONTINUE;
  3768. }
  3769. /*
  3770. * (username | realm | nonce | cnonce | nonce-count | qop digest-uri |
  3771. * response | maxbuf | charset | auth-param )
  3772. */
  3773. result = make_client_response(text, params, oparams);
  3774. if (result != SASL_OK) return result;
  3775. *clientoutlen = (unsigned) strlen(text->out_buf);
  3776. *clientout = text->out_buf;
  3777. /* check for next state (2 or 3) is done in digestmd5_client_mech_step() */
  3778. return SASL_CONTINUE;
  3779. }
  3780. static int digestmd5_client_mech_step2(client_context_t *ctext,
  3781. sasl_client_params_t *params,
  3782. const char *serverin,
  3783. unsigned serverinlen,
  3784. sasl_interact_t **prompt_need,
  3785. const char **clientout,
  3786. unsigned *clientoutlen,
  3787. sasl_out_params_t *oparams)
  3788. {
  3789. context_t *text = (context_t *) ctext;
  3790. int result = SASL_FAIL;
  3791. char **realms = NULL;
  3792. int nrealm = 0;
  3793. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3794. "DIGEST-MD5 client step 2");
  3795. if (params->props.min_ssf > params->props.max_ssf) {
  3796. return SASL_BADPARAM;
  3797. }
  3798. /* don't bother parsing the challenge more than once */
  3799. if (text->nonce == NULL) {
  3800. result = parse_server_challenge(ctext, params, serverin, serverinlen,
  3801. &realms, &nrealm);
  3802. if (result != SASL_OK) goto FreeAllocatedMem;
  3803. if (nrealm == 1) {
  3804. /* only one choice! */
  3805. if (text->realm) params->utils->free(text->realm);
  3806. text->realm = realms[0];
  3807. /* free realms */
  3808. params->utils->free(realms);
  3809. realms = NULL;
  3810. } else {
  3811. /* Save realms for later use */
  3812. text->realms = realms;
  3813. text->realm_cnt = nrealm;
  3814. }
  3815. } else {
  3816. /* Restore the list of realms */
  3817. realms = text->realms;
  3818. nrealm = text->realm_cnt;
  3819. }
  3820. result = ask_user_info(ctext, params, realms, nrealm,
  3821. prompt_need, oparams);
  3822. if (result != SASL_OK) goto FreeAllocatedMem;
  3823. /*
  3824. * (username | realm | nonce | cnonce | nonce-count | qop | digest-uri |
  3825. * response | maxbuf | charset | auth-param )
  3826. */
  3827. result = make_client_response(text, params, oparams);
  3828. if (result != SASL_OK) goto FreeAllocatedMem;
  3829. *clientoutlen = (unsigned) strlen(text->out_buf);
  3830. *clientout = text->out_buf;
  3831. text->state = 3;
  3832. result = SASL_CONTINUE;
  3833. FreeAllocatedMem:
  3834. return result;
  3835. }
  3836. static int
  3837. digestmd5_client_mech_step3(client_context_t *ctext,
  3838. sasl_client_params_t *params,
  3839. const char *serverin,
  3840. unsigned serverinlen,
  3841. sasl_interact_t **prompt_need __attribute__((unused)),
  3842. const char **clientout __attribute__((unused)),
  3843. unsigned *clientoutlen __attribute__((unused)),
  3844. sasl_out_params_t *oparams)
  3845. {
  3846. context_t *text = (context_t *) ctext;
  3847. char *in = NULL;
  3848. char *in_start;
  3849. int result = SASL_FAIL;
  3850. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3851. "DIGEST-MD5 client step 3");
  3852. /* Verify that server is really what he claims to be */
  3853. in_start = in = params->utils->malloc(serverinlen + 1);
  3854. if (in == NULL) return SASL_NOMEM;
  3855. memcpy(in, serverin, serverinlen);
  3856. in[serverinlen] = 0;
  3857. /* parse the response */
  3858. while (in[0] != '\0') {
  3859. char *name, *value;
  3860. get_pair(&in, &name, &value);
  3861. if (name == NULL) {
  3862. params->utils->seterror(params->utils->conn, 0,
  3863. "DIGEST-MD5 Received Garbage");
  3864. result = SASL_BADAUTH;
  3865. break;
  3866. }
  3867. if (*name == '\0') {
  3868. break;
  3869. }
  3870. if (strcasecmp(name, "rspauth") == 0) {
  3871. if (strcmp(text->response_value, value) != 0) {
  3872. params->utils->seterror(params->utils->conn, 0,
  3873. "DIGEST-MD5: This server wants us to believe that he knows shared secret");
  3874. result = SASL_BADSERV;
  3875. } else {
  3876. oparams->doneflag = 1;
  3877. oparams->param_version = 0;
  3878. result = SASL_OK;
  3879. }
  3880. break;
  3881. } else {
  3882. params->utils->log(params->utils->conn, SASL_LOG_DEBUG,
  3883. "DIGEST-MD5 unrecognized pair %s/%s: ignoring",
  3884. name, value);
  3885. }
  3886. }
  3887. params->utils->free(in_start);
  3888. if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
  3889. unsigned val = hash(params->serverFQDN) % text->reauth->size;
  3890. switch (result) {
  3891. case SASL_OK:
  3892. if (text->nonce_count == 1) {
  3893. /* successful initial auth, setup for future reauth */
  3894. clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
  3895. _plug_strdup(params->utils, oparams->authid,
  3896. &text->reauth->e[val].authid, NULL);
  3897. text->reauth->e[val].realm = text->realm; text->realm = NULL;
  3898. text->reauth->e[val].nonce = text->nonce; text->nonce = NULL;
  3899. text->reauth->e[val].nonce_count = text->nonce_count;
  3900. text->reauth->e[val].cnonce = text->cnonce; text->cnonce = NULL;
  3901. _plug_strdup(params->utils, params->serverFQDN,
  3902. &text->reauth->e[val].u.c.serverFQDN, NULL);
  3903. if (text->http_mode) {
  3904. /* per RFC 2617: algorithm & opaque MUST be saved */
  3905. text->reauth->e[val].u.c.algorithm = ctext->algorithm;
  3906. ctext->algorithm = NULL;
  3907. text->reauth->e[val].u.c.opaque = ctext->opaque;
  3908. ctext->opaque = NULL;
  3909. }
  3910. text->reauth->e[val].u.c.protection = ctext->protection;
  3911. text->reauth->e[val].u.c.cipher = ctext->cipher;
  3912. text->reauth->e[val].u.c.server_maxbuf = ctext->server_maxbuf;
  3913. }
  3914. else {
  3915. /* reauth, we already incremented nonce_count */
  3916. }
  3917. break;
  3918. default:
  3919. if (text->nonce_count > 1) {
  3920. /* failed reauth, clear cache */
  3921. clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
  3922. }
  3923. else {
  3924. /* failed initial auth, leave existing cache */
  3925. }
  3926. }
  3927. params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
  3928. }
  3929. return result;
  3930. }
  3931. static int digestmd5_client_mech_step(void *conn_context,
  3932. sasl_client_params_t *params,
  3933. const char *serverin,
  3934. unsigned serverinlen,
  3935. sasl_interact_t **prompt_need,
  3936. const char **clientout,
  3937. unsigned *clientoutlen,
  3938. sasl_out_params_t *oparams)
  3939. {
  3940. context_t *text = (context_t *) conn_context;
  3941. client_context_t *ctext = (client_context_t *) conn_context;
  3942. unsigned val = hash(params->serverFQDN) % text->reauth->size;
  3943. if (serverinlen > 2048) return SASL_BADPROT;
  3944. *clientout = NULL;
  3945. *clientoutlen = 0;
  3946. switch (text->state) {
  3947. case 1:
  3948. if (!serverin) {
  3949. /* here's where we attempt fast reauth if possible */
  3950. int reauth = 0;
  3951. /* check if we have saved info for this server */
  3952. if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
  3953. reauth = text->reauth->e[val].u.c.serverFQDN &&
  3954. !strcasecmp(text->reauth->e[val].u.c.serverFQDN,
  3955. params->serverFQDN);
  3956. params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
  3957. }
  3958. if (reauth) {
  3959. return digestmd5_client_mech_step1(ctext, params,
  3960. serverin, serverinlen,
  3961. prompt_need,
  3962. clientout, clientoutlen,
  3963. oparams);
  3964. }
  3965. else {
  3966. /* we don't have any reauth info, so just return
  3967. * that there is no initial client send */
  3968. text->state = 2;
  3969. return SASL_CONTINUE;
  3970. }
  3971. }
  3972. else if (!strncasecmp(serverin, "rspauth=", 8)) {
  3973. /* server accepted fast reauth */
  3974. text->state = 3;
  3975. goto step3;
  3976. }
  3977. /* fall through and respond to challenge */
  3978. text->state = 2;
  3979. /* cleanup after a failed reauth attempt */
  3980. if (params->utils->mutex_lock(text->reauth->mutex) == SASL_OK) { /* LOCK */
  3981. clear_reauth_entry(&text->reauth->e[val], CLIENT, params->utils);
  3982. params->utils->mutex_unlock(text->reauth->mutex); /* UNLOCK */
  3983. }
  3984. if (text->realm) params->utils->free(text->realm);
  3985. if (text->nonce) params->utils->free(text->nonce);
  3986. if (text->cnonce) params->utils->free(text->cnonce);
  3987. text->realm = NULL;
  3988. text->nonce = text->cnonce = NULL;
  3989. ctext->cipher = NULL;
  3990. GCC_FALLTHROUGH
  3991. case 2:
  3992. return digestmd5_client_mech_step2(ctext, params,
  3993. serverin, serverinlen,
  3994. prompt_need,
  3995. clientout, clientoutlen,
  3996. oparams);
  3997. case 3:
  3998. step3:
  3999. return digestmd5_client_mech_step3(ctext, params,
  4000. serverin, serverinlen,
  4001. prompt_need,
  4002. clientout, clientoutlen,
  4003. oparams);
  4004. default:
  4005. params->utils->log(NULL, SASL_LOG_ERR,
  4006. "Invalid DIGEST-MD5 client step %d\n", text->state);
  4007. return SASL_FAIL;
  4008. }
  4009. return SASL_FAIL; /* should never get here */
  4010. }
  4011. static void digestmd5_client_mech_dispose(void *conn_context,
  4012. const sasl_utils_t *utils)
  4013. {
  4014. client_context_t *ctext = (client_context_t *) conn_context;
  4015. if (!ctext || !utils) return;
  4016. utils->log(utils->conn, SASL_LOG_DEBUG,
  4017. "DIGEST-MD5 client mech dispose");
  4018. if (ctext->free_password) _plug_free_secret(utils, &ctext->password);
  4019. if (ctext->algorithm) utils->free(ctext->algorithm);
  4020. if (ctext->opaque) utils->free(ctext->opaque);
  4021. digestmd5_common_mech_dispose(conn_context, utils);
  4022. }
  4023. static sasl_client_plug_t digestmd5_client_plugins[] =
  4024. {
  4025. {
  4026. "DIGEST-MD5",
  4027. #ifdef WITH_RC4 /* mech_name */
  4028. 128, /* max ssf */
  4029. #elif defined(WITH_DES)
  4030. 112,
  4031. #else
  4032. 1,
  4033. #endif
  4034. SASL_SEC_NOPLAINTEXT
  4035. | SASL_SEC_NOANONYMOUS
  4036. | SASL_SEC_MUTUAL_AUTH, /* security_flags */
  4037. SASL_FEAT_NEEDSERVERFQDN
  4038. | SASL_FEAT_ALLOWS_PROXY
  4039. | SASL_FEAT_SUPPORTS_HTTP, /* features */
  4040. NULL, /* required_prompts */
  4041. &client_glob_context, /* glob_context */
  4042. &digestmd5_client_mech_new, /* mech_new */
  4043. &digestmd5_client_mech_step, /* mech_step */
  4044. &digestmd5_client_mech_dispose, /* mech_dispose */
  4045. &digestmd5_common_mech_free, /* mech_free */
  4046. NULL, /* idle */
  4047. NULL, /* spare1 */
  4048. NULL /* spare2 */
  4049. }
  4050. };
  4051. int digestmd5_client_plug_init(sasl_utils_t *utils,
  4052. int maxversion,
  4053. int *out_version,
  4054. sasl_client_plug_t **pluglist,
  4055. int *plugcount)
  4056. {
  4057. reauth_cache_t *reauth_cache;
  4058. if (maxversion < SASL_CLIENT_PLUG_VERSION)
  4059. return SASL_BADVERS;
  4060. /* reauth cache */
  4061. reauth_cache = utils->malloc(sizeof(reauth_cache_t));
  4062. if (reauth_cache == NULL)
  4063. return SASL_NOMEM;
  4064. memset(reauth_cache, 0, sizeof(reauth_cache_t));
  4065. reauth_cache->i_am = CLIENT;
  4066. /* mutex */
  4067. reauth_cache->mutex = utils->mutex_alloc();
  4068. if (!reauth_cache->mutex)
  4069. return SASL_FAIL;
  4070. /* entries */
  4071. reauth_cache->size = 10;
  4072. reauth_cache->e = utils->malloc(reauth_cache->size *
  4073. sizeof(reauth_entry_t));
  4074. if (reauth_cache->e == NULL)
  4075. return SASL_NOMEM;
  4076. memset(reauth_cache->e, 0, reauth_cache->size * sizeof(reauth_entry_t));
  4077. ((digest_glob_context_t *) digestmd5_client_plugins[0].glob_context)->reauth = reauth_cache;
  4078. *out_version = SASL_CLIENT_PLUG_VERSION;
  4079. *pluglist = digestmd5_client_plugins;
  4080. *plugcount = 1;
  4081. return SASL_OK;
  4082. }