gnutls.patch 108 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296
  1. Copyright (c) 2014-2017 Savoir-faire Linux Inc.
  2. ssl_sock: add gnutls backend
  3. This backend is mutually exclusive with the OpenSSL one, but completely
  4. compatible, and conformant to the PJSIP API. Also avoids any license issues
  5. when linking statically.
  6. The configure script is updated to select either OpenSSL or GnuTLS
  7. with --enable-ssl[='...'] and a new symbol (PJ_HAS_TLS_SOCK) is introduced
  8. to identify which backend is in use.
  9. Written by
  10. Vittorio Giovara <vittorio.giovara@savoirfairelinux.com>
  11. Philippe Proulx <philippe.proulx@savoirfairelinux.com> and
  12. Adrien Béraud <adrien.beraud@savoirfairelinux.com>
  13. on behalf of Savoir-faire Linux.
  14. ---
  15. diff -ru a/aconfigure b/aconfigure
  16. --- a/aconfigure 2017-01-25 06:23:08.000000000 -0500
  17. +++ b/aconfigure 2017-06-08 13:51:11.146810527 -0400
  18. @@ -644,6 +644,8 @@
  19. libcrypto_present
  20. libssl_present
  21. openssl_h_present
  22. +libgnutls_present
  23. +gnutls_h_present
  24. ac_ssl_has_aes_gcm
  25. ac_no_ssl
  26. ac_openh264_ldflags
  27. @@ -1482,8 +1484,8 @@
  28. package and samples location using IPPROOT and
  29. IPPSAMPLES env var or with --with-ipp and
  30. --with-ipp-samples options
  31. - --disable-ssl Exclude SSL support the build (default: autodetect)
  32. -
  33. + --enable-ssl=backend Select 'gnutls' or 'openssl' (default) to provide
  34. + SSL support (autodetect)
  35. --disable-opencore-amr Exclude OpenCORE AMR support from the build
  36. (default: autodetect)
  37. @@ -7787,17 +7789,149 @@
  38. # Check whether --enable-ssl was given.
  39. if test "${enable_ssl+set}" = set; then :
  40. - enableval=$enable_ssl;
  41. - if test "$enable_ssl" = "no"; then
  42. - ac_no_ssl=1
  43. - { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if SSL support is disabled... yes" >&5
  44. + enableval=$enable_ssl; if test "x$enableval" = "xgnutls"; then
  45. + ssl_backend="gnutls"
  46. + else
  47. + ssl_backend="openssl"
  48. + fi
  49. +fi
  50. +
  51. +
  52. +if test "x$enable_ssl" = "xno"; then
  53. + ac_no_ssl=1
  54. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Checking if SSL support is disabled... yes" >&5
  55. $as_echo "Checking if SSL support is disabled... yes" >&6; }
  56. - fi
  57. +else
  58. + if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
  59. + CFLAGS="$CFLAGS -I$with_ssl/include"
  60. + LDFLAGS="$LDFLAGS -L$with_ssl/lib"
  61. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using SSL prefix... $with_ssl" >&5
  62. +$as_echo "Using SSL prefix... $with_ssl" >&6; }
  63. + fi
  64. + if test "x$ssl_backend" = "xgnutls"; then
  65. + for ac_prog in $host-pkg-config pkg-config "python pkgconfig.py"
  66. +do
  67. + # Extract the first word of "$ac_prog", so it can be a program name with args.
  68. +set dummy $ac_prog; ac_word=$2
  69. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
  70. +$as_echo_n "checking for $ac_word... " >&6; }
  71. +if ${ac_cv_prog_PKG_CONFIG+:} false; then :
  72. + $as_echo_n "(cached) " >&6
  73. +else
  74. + if test -n "$PKG_CONFIG"; then
  75. + ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test.
  76. +else
  77. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
  78. +for as_dir in $PATH
  79. +do
  80. + IFS=$as_save_IFS
  81. + test -z "$as_dir" && as_dir=.
  82. + for ac_exec_ext in '' $ac_executable_extensions; do
  83. + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
  84. + ac_cv_prog_PKG_CONFIG="$ac_prog"
  85. + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
  86. + break 2
  87. + fi
  88. +done
  89. + done
  90. +IFS=$as_save_IFS
  91. +
  92. +fi
  93. +fi
  94. +PKG_CONFIG=$ac_cv_prog_PKG_CONFIG
  95. +if test -n "$PKG_CONFIG"; then
  96. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
  97. +$as_echo "$PKG_CONFIG" >&6; }
  98. +else
  99. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
  100. +$as_echo "no" >&6; }
  101. +fi
  102. +
  103. +
  104. + test -n "$PKG_CONFIG" && break
  105. +done
  106. +test -n "$PKG_CONFIG" || PKG_CONFIG="none"
  107. +
  108. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for GnuTLS installations.." >&5
  109. +$as_echo "checking for GnuTLS installations.." >&6; }
  110. +
  111. +
  112. + ac_fn_c_check_header_mongrel "$LINENO" "gnutls/gnutls.h" "ac_cv_header_gnutls_gnutls_h" "$ac_includes_default"
  113. +if test "x$ac_cv_header_gnutls_gnutls_h" = xyes; then :
  114. + gnutls_h_present=1
  115. +fi
  116. +
  117. +
  118. + if test "$PKG_CONFIG" != "none"; then
  119. + if $PKG_CONFIG --exists gnutls; then
  120. + LIBS="$LIBS `$PKG_CONFIG --libs gnutls`"
  121. + libgnutls_present=1
  122. + else
  123. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gnutls_certificate_set_x509_system_trust in -lgnutls" >&5
  124. +$as_echo_n "checking for gnutls_certificate_set_x509_system_trust in -lgnutls... " >&6; }
  125. +if ${ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust+:} false; then :
  126. + $as_echo_n "(cached) " >&6
  127. +else
  128. + ac_check_lib_save_LIBS=$LIBS
  129. +LIBS="-lgnutls $LIBS"
  130. +cat confdefs.h - <<_ACEOF >conftest.$ac_ext
  131. +/* end confdefs.h. */
  132. +
  133. +/* Override any GCC internal prototype to avoid an error.
  134. + Use char because int might match the return type of a GCC
  135. + builtin and then its argument prototype would still apply. */
  136. +#ifdef __cplusplus
  137. +extern "C"
  138. +#endif
  139. +char gnutls_certificate_set_x509_system_trust ();
  140. +int
  141. +main ()
  142. +{
  143. +return gnutls_certificate_set_x509_system_trust ();
  144. + ;
  145. + return 0;
  146. +}
  147. +_ACEOF
  148. +if ac_fn_c_try_link "$LINENO"; then :
  149. + ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust=yes
  150. else
  151. + ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust=no
  152. +fi
  153. +rm -f core conftest.err conftest.$ac_objext \
  154. + conftest$ac_exeext conftest.$ac_ext
  155. +LIBS=$ac_check_lib_save_LIBS
  156. +fi
  157. +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" >&5
  158. +$as_echo "$ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" >&6; }
  159. +if test "x$ac_cv_lib_gnutls_gnutls_certificate_set_x509_system_trust" = xyes; then :
  160. + libgnutls_present=1 &&
  161. + LIBS="$LIBS -lgnutls"
  162. +fi
  163. + fi
  164. + else
  165. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: *** Warning: neither pkg-config nor python is available, disabling gnutls. ***" >&5
  166. +$as_echo "*** Warning: neither pkg-config nor python is available, disabling gnutls. ***" >&6; }
  167. + fi
  168. +
  169. + if test "x$gnutls_h_present" = "x1" -a "x$libgnutls_present" = "x1"; then
  170. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: GnuTLS library found, SSL support enabled" >&5
  171. +$as_echo "GnuTLS library found, SSL support enabled" >&6; }
  172. + # PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
  173. + #AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
  174. + $as_echo "#define PJ_HAS_SSL_SOCK 1" >>confdefs.h
  175. +
  176. + $as_echo "#define PJ_HAS_TLS_SOCK 1" >>confdefs.h
  177. +
  178. + else
  179. + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ** No GnuTLS libraries found, disabling SSL support **" >&5
  180. +$as_echo "** No GnuTLS libraries found, disabling SSL support **" >&6; }
  181. + fi
  182. + else
  183. { $as_echo "$as_me:${as_lineno-$LINENO}: result: checking for OpenSSL installations.." >&5
  184. $as_echo "checking for OpenSSL installations.." >&6; }
  185. +
  186. if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
  187. CFLAGS="$CFLAGS -I$with_ssl/include"
  188. LDFLAGS="$LDFLAGS -L$with_ssl/lib"
  189. @@ -7971,11 +8105,10 @@
  190. { $as_echo "$as_me:${as_lineno-$LINENO}: result: ** OpenSSL libraries not found, disabling SSL support **" >&5
  191. $as_echo "** OpenSSL libraries not found, disabling SSL support **" >&6; }
  192. fi
  193. -
  194. + fi
  195. fi
  196. -
  197. # Check whether --with-opencore-amrnb was given.
  198. if test "${with_opencore_amrnb+set}" = set; then :
  199. withval=$with_opencore_amrnb; as_fn_error $? "This option is obsolete and replaced by --with-opencore-amr=DIR" "$LINENO" 5
  200. diff -ru a/aconfigure.ac b/aconfigure.ac
  201. --- a/aconfigure.ac 2017-01-25 06:23:08.000000000 -0500
  202. +++ b/aconfigure.ac 2017-06-08 13:28:17.138135490 -0400
  203. @@ -1533,18 +1533,59 @@
  204. dnl # Include SSL support
  205. AC_SUBST(ac_no_ssl)
  206. AC_SUBST(ac_ssl_has_aes_gcm,0)
  207. -AC_ARG_ENABLE(ssl,
  208. - AS_HELP_STRING([--disable-ssl],
  209. - [Exclude SSL support the build (default: autodetect)])
  210. - ,
  211. - [
  212. - if test "$enable_ssl" = "no"; then
  213. - [ac_no_ssl=1]
  214. - AC_MSG_RESULT([Checking if SSL support is disabled... yes])
  215. - fi
  216. - ],
  217. - [
  218. +AC_ARG_ENABLE([ssl],
  219. + AS_HELP_STRING([--enable-ssl[=backend]],
  220. + [Select 'gnutls' or 'openssl' (default) to provide SSL support (autodetect)]),
  221. + [ if test "x$enableval" = "xgnutls"; then
  222. + [ssl_backend="gnutls"]
  223. + else
  224. + [ssl_backend="openssl"]
  225. + fi ])
  226. +
  227. +if test "x$enable_ssl" = "xno"; then
  228. + [ac_no_ssl=1]
  229. + AC_MSG_RESULT([Checking if SSL support is disabled... yes])
  230. +else
  231. + if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
  232. + CFLAGS="$CFLAGS -I$with_ssl/include"
  233. + LDFLAGS="$LDFLAGS -L$with_ssl/lib"
  234. + AC_MSG_RESULT([Using SSL prefix... $with_ssl])
  235. + fi
  236. + if test "x$ssl_backend" = "xgnutls"; then
  237. + AC_CHECK_PROGS(PKG_CONFIG,
  238. + $host-pkg-config pkg-config "python pkgconfig.py",
  239. + none)
  240. + AC_MSG_RESULT([checking for GnuTLS installations..])
  241. + AC_SUBST(gnutls_h_present)
  242. + AC_SUBST(libgnutls_present)
  243. + AC_CHECK_HEADER(gnutls/gnutls.h, [gnutls_h_present=1])
  244. +
  245. + if test "$PKG_CONFIG" != "none"; then
  246. + if $PKG_CONFIG --exists gnutls; then
  247. + LIBS="$LIBS `$PKG_CONFIG --libs gnutls`"
  248. + libgnutls_present=1
  249. + else
  250. + AC_CHECK_LIB(gnutls,
  251. + gnutls_certificate_set_x509_system_trust,
  252. + [libgnutls_present=1 &&
  253. + LIBS="$LIBS -lgnutls"])
  254. + fi
  255. + else
  256. + AC_MSG_RESULT([*** Warning: neither pkg-config nor python is available, disabling gnutls. ***])
  257. + fi
  258. +
  259. + if test "x$gnutls_h_present" = "x1" -a "x$libgnutls_present" = "x1"; then
  260. + AC_MSG_RESULT([GnuTLS library found, SSL support enabled])
  261. + # PJSIP_HAS_TLS_TRANSPORT setting follows PJ_HAS_SSL_SOCK
  262. + #AC_DEFINE(PJSIP_HAS_TLS_TRANSPORT, 1)
  263. + AC_DEFINE(PJ_HAS_SSL_SOCK, 1)
  264. + AC_DEFINE(PJ_HAS_TLS_SOCK, 1)
  265. + else
  266. + AC_MSG_RESULT([** No GnuTLS libraries found, disabling SSL support **])
  267. + fi
  268. + else
  269. AC_MSG_RESULT([checking for OpenSSL installations..])
  270. +
  271. if test "x$with_ssl" != "xno" -a "x$with_ssl" != "x"; then
  272. CFLAGS="$CFLAGS -I$with_ssl/include"
  273. LDFLAGS="$LDFLAGS -L$with_ssl/lib"
  274. @@ -1578,7 +1619,8 @@
  275. else
  276. AC_MSG_RESULT([** OpenSSL libraries not found, disabling SSL support **])
  277. fi
  278. - ])
  279. + fi
  280. +fi
  281. dnl # Obsolete option --with-opencore-amrnb
  282. AC_ARG_WITH(opencore-amrnb,
  283. diff -ru a/pjlib/build/Makefile b/pjlib/build/Makefile
  284. --- a/pjlib/build/Makefile 2016-10-05 05:52:39.000000000 -0400
  285. +++ b/pjlib/build/Makefile 2017-06-08 13:30:20.702138591 -0400
  286. @@ -35,7 +35,7 @@
  287. guid.o hash.o ip_helper_generic.o list.o lock.o log.o os_time_common.o \
  288. os_info.o pool.o pool_buf.o pool_caching.o pool_dbg.o rand.o \
  289. rbtree.o sock_common.o sock_qos_common.o \
  290. - ssl_sock_common.o ssl_sock_ossl.o ssl_sock_dump.o \
  291. + ssl_sock_common.o ssl_sock_ossl.o ssl_sock_gtls.o ssl_sock_dump.o \
  292. string.o timer.o types.o
  293. export PJLIB_CFLAGS += $(_CFLAGS)
  294. export PJLIB_CXXFLAGS += $(_CXXFLAGS)
  295. diff -ru a/pjlib/include/pj/compat/os_auto.h.in b/pjlib/include/pj/compat/os_auto.h.in
  296. --- a/pjlib/include/pj/compat/os_auto.h.in 2017-01-24 00:36:50.000000000 -0500
  297. +++ b/pjlib/include/pj/compat/os_auto.h.in 2017-06-08 13:31:04.976064779 -0400
  298. @@ -219,6 +219,9 @@
  299. #ifndef PJ_HAS_SSL_SOCK
  300. #undef PJ_HAS_SSL_SOCK
  301. #endif
  302. +#ifndef PJ_HAS_TLS_SOCK
  303. +#undef PJ_HAS_TLS_SOCK
  304. +#endif
  305. #endif /* __PJ_COMPAT_OS_AUTO_H__ */
  306. diff -ru a/pjlib/include/pj/config.h b/pjlib/include/pj/config.h
  307. --- a/pjlib/include/pj/config.h 2017-01-25 21:29:59.000000000 -0500
  308. +++ b/pjlib/include/pj/config.h 2017-06-08 13:34:27.642149351 -0400
  309. @@ -888,7 +888,7 @@
  310. /**
  311. * Enable secure socket. For most platforms, this is implemented using
  312. - * OpenSSL, so this will require OpenSSL to be installed. For Symbian
  313. + * OpenSSL or GnuTLS, so this will require OpenSSL or GnuTLS to be installed. For Symbian
  314. * platform, this is implemented natively using CSecureSocket.
  315. *
  316. * Default: 0 (for now)
  317. @@ -896,6 +896,10 @@
  318. #ifndef PJ_HAS_SSL_SOCK
  319. # define PJ_HAS_SSL_SOCK 0
  320. #endif
  321. +// When set to 1 secure sockets will use the GnuTLS backend than OpenSSL
  322. +#ifndef PJ_HAS_TLS_SOCK
  323. +# define PJ_HAS_TLS_SOCK 0
  324. +#endif
  325. /**
  326. diff -ru a/pjlib/include/pj/ssl_sock.h b/pjlib/include/pj/ssl_sock.h
  327. --- a/pjlib/include/pj/ssl_sock.h 2016-10-27 03:58:01.000000000 -0400
  328. +++ b/pjlib/include/pj/ssl_sock.h 2017-06-08 13:36:16.448510381 -0400
  329. @@ -184,6 +184,10 @@
  330. pj_str_t raw; /**< Raw certificate in PEM format, only
  331. available for remote certificate. */
  332. + struct {
  333. + unsigned cnt; /**< # of entry */
  334. + pj_str_t* cert_raw;
  335. + } raw_chain;
  336. } pj_ssl_cert_info;
  337. diff -ru a/pjlib/src/pj/ssl_sock_common.c b/pjlib/src/pj/ssl_sock_common.c
  338. --- a/pjlib/src/pj/ssl_sock_common.c 2016-10-27 03:58:01.000000000 -0400
  339. +++ b/pjlib/src/pj/ssl_sock_common.c 2017-06-08 13:37:17.171037628 -0400
  340. @@ -35,7 +35,12 @@
  341. param->async_cnt = 1;
  342. param->concurrency = -1;
  343. param->whole_data = PJ_TRUE;
  344. +#if defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 1
  345. + // GnuTLS is allowed to send bigger chunks
  346. + param->send_buffer_size = 65536;
  347. +#else
  348. param->send_buffer_size = 8192;
  349. +#endif
  350. #if !defined(PJ_SYMBIAN) || PJ_SYMBIAN==0
  351. param->read_buffer_size = 1500;
  352. #endif
  353. diff --git a/pjlib/src/pj/ssl_sock_gtls.c b/pjlib/src/pj/ssl_sock_gtls.c
  354. new file mode 100644
  355. index 0000000..37bcaba
  356. --- /dev/null
  357. +++ b/pjlib/src/pj/ssl_sock_gtls.c
  358. @@ -0,0 +1,2877 @@
  359. +/* $Id$ */
  360. +/*
  361. + * Copyright (C) 2014-2016 Savoir-faire Linux. (https://www.savoirfairelinux.com)
  362. + *
  363. + * This program is free software; you can redistribute it and/or modify
  364. + * it under the terms of the GNU General Public License as published by
  365. + * the Free Software Foundation; either version 2 of the License, or
  366. + * (at your option) any later version.
  367. + *
  368. + * This program is distributed in the hope that it will be useful,
  369. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  370. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  371. + * GNU General Public License for more details.
  372. + *
  373. + * You should have received a copy of the GNU General Public License
  374. + * along with this program; if not, write to the Free Software
  375. + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  376. + */
  377. +
  378. +#include <pj/ssl_sock.h>
  379. +#include <pj/activesock.h>
  380. +#include <pj/compat/socket.h>
  381. +#include <pj/assert.h>
  382. +#include <pj/errno.h>
  383. +#include <pj/list.h>
  384. +#include <pj/lock.h>
  385. +#include <pj/log.h>
  386. +#include <pj/math.h>
  387. +#include <pj/os.h>
  388. +#include <pj/pool.h>
  389. +#include <pj/string.h>
  390. +#include <pj/timer.h>
  391. +#include <pj/file_io.h>
  392. +
  393. +#if GNUTLS_VERSION_NUMBER < 0x030306 && !defined(_MSC_VER)
  394. +#include <dirent.h>
  395. +#endif
  396. +
  397. +#include <errno.h>
  398. +
  399. +/* Only build when PJ_HAS_SSL_SOCK and PJ_HAS_TLS_SOCK are enabled */
  400. +#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
  401. + defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK != 0
  402. +
  403. +#define THIS_FILE "ssl_sock_gtls.c"
  404. +
  405. +/* Workaround for ticket #985 */
  406. +#define DELAYED_CLOSE_TIMEOUT 200
  407. +
  408. +/* Maximum ciphers */
  409. +#define MAX_CIPHERS 100
  410. +
  411. +/* Standard trust locations */
  412. +#define TRUST_STORE_FILE1 "/etc/ssl/certs/ca-certificates.crt"
  413. +#define TRUST_STORE_FILE2 "/etc/ssl/certs/ca-bundle.crt"
  414. +
  415. +/* Debugging output level for GnuTLS only */
  416. +#define GNUTLS_LOG_LEVEL 0
  417. +
  418. +/* GnuTLS includes */
  419. +#include <gnutls/gnutls.h>
  420. +#include <gnutls/x509.h>
  421. +#include <gnutls/abstract.h>
  422. +
  423. +#ifdef _MSC_VER
  424. +# pragma comment( lib, "libgnutls")
  425. +#endif
  426. +
  427. +
  428. +/* TLS state enumeration. */
  429. +enum tls_connection_state {
  430. + TLS_STATE_NULL,
  431. + TLS_STATE_HANDSHAKING,
  432. + TLS_STATE_ESTABLISHED
  433. +};
  434. +
  435. +/* Internal timer types. */
  436. +enum timer_id {
  437. + TIMER_NONE,
  438. + TIMER_HANDSHAKE_TIMEOUT,
  439. + TIMER_CLOSE
  440. +};
  441. +
  442. +/* Structure of SSL socket read buffer. */
  443. +typedef struct read_data_t {
  444. + void *data;
  445. + pj_size_t len;
  446. +} read_data_t;
  447. +
  448. +/*
  449. + * Get the offset of pointer to read-buffer of SSL socket from read-buffer
  450. + * of active socket. Note that both SSL socket and active socket employ
  451. + * different but correlated read-buffers (as much as async_cnt for each),
  452. + * and to make it easier/faster to find corresponding SSL socket's read-buffer
  453. + * from known active socket's read-buffer, the pointer of corresponding
  454. + * SSL socket's read-buffer is stored right after the end of active socket's
  455. + * read-buffer.
  456. + */
  457. +#define OFFSET_OF_READ_DATA_PTR(ssock, asock_rbuf) \
  458. + (read_data_t**) \
  459. + ((pj_int8_t *)(asock_rbuf) + \
  460. + ssock->param.read_buffer_size)
  461. +
  462. +/* Structure of SSL socket write data. */
  463. +typedef struct write_data_t {
  464. + PJ_DECL_LIST_MEMBER(struct write_data_t);
  465. + pj_ioqueue_op_key_t key;
  466. + pj_size_t record_len;
  467. + pj_ioqueue_op_key_t *app_key;
  468. + pj_size_t plain_data_len;
  469. + pj_size_t data_len;
  470. + unsigned flags;
  471. + union {
  472. + char content[1];
  473. + const char *ptr;
  474. + } data;
  475. +} write_data_t;
  476. +
  477. +
  478. +/* Structure of SSL socket write buffer (circular buffer). */
  479. +typedef struct send_buf_t {
  480. + char *buf;
  481. + pj_size_t max_len;
  482. + char *start;
  483. + pj_size_t len;
  484. +} send_buf_t;
  485. +
  486. +
  487. +/* Circular buffer object */
  488. +typedef struct circ_buf_t {
  489. + pj_size_t cap; /* maximum number of elements (must be power of 2) */
  490. + pj_size_t readp; /* index of oldest element */
  491. + pj_size_t writep; /* index at which to write new element */
  492. + pj_size_t size; /* number of elements */
  493. + pj_uint8_t *buf; /* data buffer */
  494. + pj_pool_t *pool; /* where new allocations will take place */
  495. +} circ_buf_t;
  496. +
  497. +
  498. +/* Secure socket structure definition. */
  499. +struct pj_ssl_sock_t {
  500. + pj_pool_t *pool;
  501. + pj_ssl_sock_t *parent;
  502. + pj_ssl_sock_param param;
  503. + pj_ssl_sock_param newsock_param;
  504. + pj_ssl_cert_t *cert;
  505. +
  506. + pj_ssl_cert_info local_cert_info;
  507. + pj_ssl_cert_info remote_cert_info;
  508. +
  509. + pj_bool_t is_server;
  510. + enum tls_connection_state connection_state;
  511. + pj_ioqueue_op_key_t handshake_op_key;
  512. + pj_timer_entry timer;
  513. + pj_status_t verify_status;
  514. +
  515. + int last_err;
  516. +
  517. + pj_sock_t sock;
  518. + pj_activesock_t *asock;
  519. +
  520. + pj_sockaddr local_addr;
  521. + pj_sockaddr rem_addr;
  522. + int addr_len;
  523. +
  524. + pj_bool_t read_started;
  525. + pj_size_t read_size;
  526. + pj_uint32_t read_flags;
  527. + void **asock_rbuf;
  528. + read_data_t *ssock_rbuf;
  529. +
  530. + write_data_t write_pending; /* list of pending writes */
  531. + write_data_t write_pending_empty; /* cache for write_pending */
  532. + pj_bool_t flushing_write_pend; /* flag of flushing is ongoing */
  533. + send_buf_t send_buf;
  534. + write_data_t send_pending; /* list of pending write to network */
  535. +
  536. + gnutls_session_t session;
  537. + gnutls_certificate_credentials_t xcred;
  538. +
  539. + circ_buf_t circ_buf_input;
  540. + pj_lock_t *circ_buf_input_mutex;
  541. +
  542. + circ_buf_t circ_buf_output;
  543. + pj_lock_t *circ_buf_output_mutex;
  544. +
  545. + int tls_init_count; /* library initialization counter */
  546. +};
  547. +
  548. +
  549. +/* Certificate/credential structure definition. */
  550. +struct pj_ssl_cert_t {
  551. + pj_str_t CA_file;
  552. + pj_str_t CA_path;
  553. + pj_str_t cert_file;
  554. + pj_str_t privkey_file;
  555. + pj_str_t privkey_pass;
  556. +};
  557. +
  558. +/* GnuTLS available ciphers */
  559. +static unsigned tls_available_ciphers;
  560. +
  561. +/* Array of id/names for available ciphers */
  562. +static struct tls_ciphers_t {
  563. + pj_ssl_cipher id;
  564. + const char *name;
  565. +} tls_ciphers[MAX_CIPHERS];
  566. +
  567. +/* Last error reported somehow */
  568. +static int tls_last_error;
  569. +
  570. +
  571. +/*
  572. + *******************************************************************
  573. + * Circular buffer functions.
  574. + *******************************************************************
  575. + */
  576. +
  577. +static pj_status_t circ_init(pj_pool_factory *factory,
  578. + circ_buf_t *cb, pj_size_t cap)
  579. +{
  580. + cb->cap = cap;
  581. + cb->readp = 0;
  582. + cb->writep = 0;
  583. + cb->size = 0;
  584. +
  585. + /* Initial pool holding the buffer elements */
  586. + cb->pool = pj_pool_create(factory, "tls-circ%p", cap, cap, NULL);
  587. + if (!cb->pool)
  588. + return PJ_ENOMEM;
  589. +
  590. + /* Allocate circular buffer */
  591. + cb->buf = pj_pool_alloc(cb->pool, cap);
  592. + if (!cb->buf) {
  593. + pj_pool_release(cb->pool);
  594. + return PJ_ENOMEM;
  595. + }
  596. +
  597. + return PJ_SUCCESS;
  598. +}
  599. +
  600. +static void circ_deinit(circ_buf_t *cb)
  601. +{
  602. + if (cb->pool) {
  603. + pj_pool_release(cb->pool);
  604. + cb->pool = NULL;
  605. + }
  606. +}
  607. +
  608. +static pj_bool_t circ_empty(const circ_buf_t *cb)
  609. +{
  610. + return cb->size == 0;
  611. +}
  612. +
  613. +static pj_size_t circ_size(const circ_buf_t *cb)
  614. +{
  615. + return cb->size;
  616. +}
  617. +
  618. +static pj_size_t circ_avail(const circ_buf_t *cb)
  619. +{
  620. + return cb->cap - cb->size;
  621. +}
  622. +
  623. +static void circ_read(circ_buf_t *cb, pj_uint8_t *dst, pj_size_t len)
  624. +{
  625. + pj_size_t size_after = cb->cap - cb->readp;
  626. + pj_size_t tbc = PJ_MIN(size_after, len);
  627. + pj_size_t rem = len - tbc;
  628. +
  629. + pj_memcpy(dst, cb->buf + cb->readp, tbc);
  630. + pj_memcpy(dst + tbc, cb->buf, rem);
  631. +
  632. + cb->readp += len;
  633. + cb->readp &= (cb->cap - 1);
  634. +
  635. + cb->size -= len;
  636. +}
  637. +
  638. +static pj_status_t circ_write(circ_buf_t *cb,
  639. + const pj_uint8_t *src, pj_size_t len)
  640. +{
  641. + /* Overflow condition: resize */
  642. + if (len > circ_avail(cb)) {
  643. + /* Minimum required capacity */
  644. + pj_size_t min_cap = len + cb->size;
  645. +
  646. + /* Next 32-bit power of two */
  647. + min_cap--;
  648. + min_cap |= min_cap >> 1;
  649. + min_cap |= min_cap >> 2;
  650. + min_cap |= min_cap >> 4;
  651. + min_cap |= min_cap >> 8;
  652. + min_cap |= min_cap >> 16;
  653. + min_cap++;
  654. +
  655. + /* Create a new pool to hold a bigger buffer, using the same factory */
  656. + pj_pool_t *pool = pj_pool_create(cb->pool->factory, "tls-circ%p",
  657. + min_cap, min_cap, NULL);
  658. + if (!pool)
  659. + return PJ_ENOMEM;
  660. +
  661. + /* Allocate our new buffer */
  662. + pj_uint8_t *buf = pj_pool_alloc(pool, min_cap);
  663. + if (!buf) {
  664. + pj_pool_release(pool);
  665. + return PJ_ENOMEM;
  666. + }
  667. +
  668. + /* Save old size, which we shall restore after the next read */
  669. + pj_size_t old_size = cb->size;
  670. +
  671. + /* Copy old data into beginning of new buffer */
  672. + circ_read(cb, buf, cb->size);
  673. +
  674. + /* Restore old size now */
  675. + cb->size = old_size;
  676. +
  677. + /* Release the previous pool */
  678. + pj_pool_release(cb->pool);
  679. +
  680. + /* Update circular buffer members */
  681. + cb->pool = pool;
  682. + cb->buf = buf;
  683. + cb->readp = 0;
  684. + cb->writep = cb->size;
  685. + cb->cap = min_cap;
  686. + }
  687. +
  688. + pj_size_t size_after = cb->cap - cb->writep;
  689. + pj_size_t tbc = PJ_MIN(size_after, len);
  690. + pj_size_t rem = len - tbc;
  691. +
  692. + pj_memcpy(cb->buf + cb->writep, src, tbc);
  693. + pj_memcpy(cb->buf, src + tbc, rem);
  694. +
  695. + cb->writep += len;
  696. + cb->writep &= (cb->cap - 1);
  697. +
  698. + cb->size += len;
  699. +
  700. + return PJ_SUCCESS;
  701. +}
  702. +
  703. +
  704. +/*
  705. + *******************************************************************
  706. + * Static/internal functions.
  707. + *******************************************************************
  708. + */
  709. +
  710. +/* Convert from GnuTLS error to pj_status_t. */
  711. +static pj_status_t tls_status_from_err(pj_ssl_sock_t *ssock, int err)
  712. +{
  713. + pj_status_t status;
  714. +
  715. + switch (err) {
  716. + case GNUTLS_E_SUCCESS:
  717. + status = PJ_SUCCESS;
  718. + break;
  719. + case GNUTLS_E_MEMORY_ERROR:
  720. + status = PJ_ENOMEM;
  721. + break;
  722. + case GNUTLS_E_LARGE_PACKET:
  723. + status = PJ_ETOOBIG;
  724. + break;
  725. + case GNUTLS_E_NO_CERTIFICATE_FOUND:
  726. + status = PJ_ENOTFOUND;
  727. + break;
  728. + case GNUTLS_E_SESSION_EOF:
  729. + status = PJ_EEOF;
  730. + break;
  731. + case GNUTLS_E_HANDSHAKE_TOO_LARGE:
  732. + status = PJ_ETOOBIG;
  733. + break;
  734. + case GNUTLS_E_EXPIRED:
  735. + status = PJ_EGONE;
  736. + break;
  737. + case GNUTLS_E_TIMEDOUT:
  738. + status = PJ_ETIMEDOUT;
  739. + break;
  740. + case GNUTLS_E_PREMATURE_TERMINATION:
  741. + status = PJ_ECANCELLED;
  742. + break;
  743. + case GNUTLS_E_INTERNAL_ERROR:
  744. + case GNUTLS_E_UNIMPLEMENTED_FEATURE:
  745. + status = PJ_EBUG;
  746. + break;
  747. + case GNUTLS_E_AGAIN:
  748. + case GNUTLS_E_INTERRUPTED:
  749. + case GNUTLS_E_REHANDSHAKE:
  750. + status = PJ_EPENDING;
  751. + break;
  752. + case GNUTLS_E_TOO_MANY_EMPTY_PACKETS:
  753. + case GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS:
  754. + case GNUTLS_E_RECORD_LIMIT_REACHED:
  755. + status = PJ_ETOOMANY;
  756. + break;
  757. + case GNUTLS_E_UNSUPPORTED_VERSION_PACKET:
  758. + case GNUTLS_E_UNSUPPORTED_SIGNATURE_ALGORITHM:
  759. + case GNUTLS_E_UNSUPPORTED_CERTIFICATE_TYPE:
  760. + case GNUTLS_E_X509_UNSUPPORTED_ATTRIBUTE:
  761. + case GNUTLS_E_X509_UNSUPPORTED_EXTENSION:
  762. + case GNUTLS_E_X509_UNSUPPORTED_CRITICAL_EXTENSION:
  763. + status = PJ_ENOTSUP;
  764. + break;
  765. + case GNUTLS_E_INVALID_SESSION:
  766. + case GNUTLS_E_INVALID_REQUEST:
  767. + case GNUTLS_E_INVALID_PASSWORD:
  768. + case GNUTLS_E_ILLEGAL_PARAMETER:
  769. + case GNUTLS_E_RECEIVED_ILLEGAL_EXTENSION:
  770. + case GNUTLS_E_UNEXPECTED_PACKET:
  771. + case GNUTLS_E_UNEXPECTED_PACKET_LENGTH:
  772. + case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
  773. + case GNUTLS_E_UNWANTED_ALGORITHM:
  774. + case GNUTLS_E_USER_ERROR:
  775. + status = PJ_EINVAL;
  776. + break;
  777. + default:
  778. + status = PJ_EUNKNOWN;
  779. + break;
  780. + }
  781. +
  782. + /* Not thread safe */
  783. + tls_last_error = err;
  784. + if (ssock)
  785. + ssock->last_err = err;
  786. + return status;
  787. +}
  788. +
  789. +
  790. +/* Get error string from GnuTLS using tls_last_error */
  791. +static pj_str_t tls_strerror(pj_status_t status,
  792. + char *buf, pj_size_t bufsize)
  793. +{
  794. + pj_str_t errstr;
  795. + const char *tmp = gnutls_strerror(tls_last_error);
  796. +
  797. +#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
  798. + if (tmp) {
  799. + pj_ansi_strncpy(buf, tmp, bufsize);
  800. + errstr = pj_str(buf);
  801. + return errstr;
  802. + }
  803. +#endif /* PJ_HAS_ERROR_STRING */
  804. +
  805. + errstr.ptr = buf;
  806. + errstr.slen = pj_ansi_snprintf(buf, bufsize, "GnuTLS error %d: %s",
  807. + tls_last_error, tmp);
  808. + if (errstr.slen < 1 || errstr.slen >= (int) bufsize)
  809. + errstr.slen = bufsize - 1;
  810. +
  811. + return errstr;
  812. +}
  813. +
  814. +
  815. +/* Initialize GnuTLS. */
  816. +static pj_status_t tls_init(void)
  817. +{
  818. + /* Register error subsystem */
  819. + pj_status_t status = pj_register_strerror(PJ_ERRNO_START_USER +
  820. + PJ_ERRNO_SPACE_SIZE * 6,
  821. + PJ_ERRNO_SPACE_SIZE,
  822. + &tls_strerror);
  823. + pj_assert(status == PJ_SUCCESS);
  824. +
  825. + /* Init GnuTLS library */
  826. + int ret = gnutls_global_init();
  827. + if (ret < 0)
  828. + return tls_status_from_err(NULL, ret);
  829. +
  830. + /* Init available ciphers */
  831. + if (!tls_available_ciphers) {
  832. + unsigned int i;
  833. +
  834. + for (i = 0; ; i++) {
  835. + unsigned char id[2];
  836. + const char *suite = gnutls_cipher_suite_info(i, (unsigned char *)id,
  837. + NULL, NULL, NULL, NULL);
  838. + tls_ciphers[i].id = 0;
  839. + /* usually the array size is bigger than the number of available
  840. + * ciphers anyway, so by checking here we can exit the loop as soon
  841. + * as either all ciphers have been added or the array is full */
  842. + if (suite && i < PJ_ARRAY_SIZE(tls_ciphers)) {
  843. + tls_ciphers[i].id = (pj_ssl_cipher)
  844. + (pj_uint32_t) ((id[0] << 8) | id[1]);
  845. + tls_ciphers[i].name = suite;
  846. + } else
  847. + break;
  848. + }
  849. +
  850. + tls_available_ciphers = i;
  851. + }
  852. +
  853. + return PJ_SUCCESS;
  854. +}
  855. +
  856. +
  857. +/* Shutdown GnuTLS */
  858. +static void tls_deinit(void)
  859. +{
  860. + gnutls_global_deinit();
  861. +}
  862. +
  863. +
  864. +/* Callback invoked every time a certificate has to be validated. */
  865. +static int tls_cert_verify_cb(gnutls_session_t session)
  866. +{
  867. + pj_ssl_sock_t *ssock;
  868. + unsigned int status;
  869. + int ret;
  870. +
  871. + /* Get SSL socket instance */
  872. + ssock = (pj_ssl_sock_t *)gnutls_session_get_ptr(session);
  873. + pj_assert(ssock);
  874. +
  875. + /* Support only x509 format */
  876. + ret = gnutls_certificate_type_get(session) != GNUTLS_CRT_X509;
  877. + if (ret < 0) {
  878. + ssock->verify_status |= PJ_SSL_CERT_EINVALID_FORMAT;
  879. + return GNUTLS_E_CERTIFICATE_ERROR;
  880. + }
  881. +
  882. + /* Store verification status */
  883. + ret = gnutls_certificate_verify_peers2(session, &status);
  884. + if (ret < 0) {
  885. + ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
  886. + return GNUTLS_E_CERTIFICATE_ERROR;
  887. + }
  888. + if (ssock->param.verify_peer) {
  889. + if (status & GNUTLS_CERT_INVALID) {
  890. + if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
  891. + ssock->verify_status |= PJ_SSL_CERT_EISSUER_NOT_FOUND;
  892. + else if (status & GNUTLS_CERT_EXPIRED ||
  893. + status & GNUTLS_CERT_NOT_ACTIVATED)
  894. + ssock->verify_status |= PJ_SSL_CERT_EVALIDITY_PERIOD;
  895. + else if (status & GNUTLS_CERT_SIGNER_NOT_CA ||
  896. + status & GNUTLS_CERT_INSECURE_ALGORITHM)
  897. + ssock->verify_status |= PJ_SSL_CERT_EUNTRUSTED;
  898. + else if (status & GNUTLS_CERT_UNEXPECTED_OWNER ||
  899. + status & GNUTLS_CERT_MISMATCH)
  900. + ssock->verify_status |= PJ_SSL_CERT_EISSUER_MISMATCH;
  901. + else if (status & GNUTLS_CERT_REVOKED)
  902. + ssock->verify_status |= PJ_SSL_CERT_EREVOKED;
  903. + else
  904. + ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
  905. +
  906. + return GNUTLS_E_CERTIFICATE_ERROR;
  907. + }
  908. +
  909. + /* When verification is not requested just return ok here, however
  910. + * applications can still get the verification status. */
  911. + gnutls_x509_crt_t cert;
  912. + unsigned int cert_list_size;
  913. + const gnutls_datum_t *cert_list;
  914. + int ret;
  915. +
  916. + ret = gnutls_x509_crt_init(&cert);
  917. + if (ret < 0)
  918. + goto out;
  919. +
  920. + cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
  921. + if (cert_list == NULL) {
  922. + ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
  923. + goto out;
  924. + }
  925. +
  926. + /* TODO: verify whole chain perhaps? */
  927. + ret = gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER);
  928. + if (ret < 0)
  929. + ret = gnutls_x509_crt_import(cert, &cert_list[0],
  930. + GNUTLS_X509_FMT_PEM);
  931. + if (ret < 0) {
  932. + ssock->verify_status |= PJ_SSL_CERT_EINVALID_FORMAT;
  933. + goto out;
  934. + }
  935. + ret = gnutls_x509_crt_check_hostname(cert, ssock->param.server_name.ptr);
  936. + if (ret < 0)
  937. + goto out;
  938. +
  939. + gnutls_x509_crt_deinit(cert);
  940. +
  941. + /* notify GnuTLS to continue handshake normally */
  942. + return GNUTLS_E_SUCCESS;
  943. +
  944. +out:
  945. + tls_last_error = ret;
  946. + ssock->verify_status |= PJ_SSL_CERT_EUNKNOWN;
  947. + return GNUTLS_E_CERTIFICATE_ERROR;
  948. + }
  949. +
  950. + return GNUTLS_E_SUCCESS;
  951. +}
  952. +
  953. +
  954. +/* gnutls_handshake() and gnutls_record_send() will call this function to
  955. + * send/write (encrypted) data */
  956. +static ssize_t tls_data_push(gnutls_transport_ptr_t ptr,
  957. + const void *data, size_t len)
  958. +{
  959. + pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)ptr;
  960. +
  961. + pj_lock_acquire(ssock->circ_buf_output_mutex);
  962. + if (circ_write(&ssock->circ_buf_output, data, len) != PJ_SUCCESS) {
  963. + pj_lock_release(ssock->circ_buf_output_mutex);
  964. +
  965. + gnutls_transport_set_errno(ssock->session, ENOMEM);
  966. + return -1;
  967. + }
  968. +
  969. + pj_lock_release(ssock->circ_buf_output_mutex);
  970. +
  971. + return len;
  972. +}
  973. +
  974. +
  975. +/* gnutls_handshake() and gnutls_record_recv() will call this function to
  976. + * receive/read (encrypted) data */
  977. +static ssize_t tls_data_pull(gnutls_transport_ptr_t ptr,
  978. + void *data, pj_size_t len)
  979. +{
  980. + pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)ptr;
  981. +
  982. + pj_lock_acquire(ssock->circ_buf_input_mutex);
  983. +
  984. + if (circ_empty(&ssock->circ_buf_input)) {
  985. + pj_lock_release(ssock->circ_buf_input_mutex);
  986. +
  987. + /* Data buffers not yet filled */
  988. + gnutls_transport_set_errno(ssock->session, EAGAIN);
  989. + return -1;
  990. + }
  991. +
  992. + pj_size_t circ_buf_size = circ_size(&ssock->circ_buf_input);
  993. + pj_size_t read_size = PJ_MIN(circ_buf_size, len);
  994. +
  995. + circ_read(&ssock->circ_buf_input, data, read_size);
  996. +
  997. + pj_lock_release(ssock->circ_buf_input_mutex);
  998. +
  999. + return read_size;
  1000. +}
  1001. +
  1002. +
  1003. +/* Append a string to the priority string, only once. */
  1004. +static pj_status_t tls_str_append_once(pj_str_t *dst, pj_str_t *src)
  1005. +{
  1006. + if (pj_strstr(dst, src) == NULL) {
  1007. + /* Check buffer size */
  1008. + if (dst->slen + src->slen + 3 > 1024)
  1009. + return PJ_ETOOMANY;
  1010. +
  1011. + pj_strcat2(dst, ":+");
  1012. + pj_strcat(dst, src);
  1013. + }
  1014. + return PJ_SUCCESS;
  1015. +}
  1016. +
  1017. +
  1018. +/* Generate priority string with user preference order. */
  1019. +static pj_status_t tls_priorities_set(pj_ssl_sock_t *ssock)
  1020. +{
  1021. + char buf[1024];
  1022. + char priority_buf[256];
  1023. + pj_str_t cipher_list;
  1024. + pj_str_t compression = pj_str("COMP-NULL");
  1025. + pj_str_t server = pj_str(":%SERVER_PRECEDENCE");
  1026. + int i, j, ret;
  1027. + pj_str_t priority;
  1028. + const char *err;
  1029. +
  1030. + pj_strset(&cipher_list, buf, 0);
  1031. + pj_strset(&priority, priority_buf, 0);
  1032. +
  1033. + /* For each level, enable only the requested protocol */
  1034. + pj_strcat2(&priority, "NORMAL:");
  1035. + if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1_2) {
  1036. + pj_strcat2(&priority, "+VERS-TLS1.2:");
  1037. + }
  1038. + if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1_1) {
  1039. + pj_strcat2(&priority, "+VERS-TLS1.1:");
  1040. + }
  1041. + if (ssock->param.proto & PJ_SSL_SOCK_PROTO_TLS1) {
  1042. + pj_strcat2(&priority, "+VERS-TLS1.0:");
  1043. + }
  1044. + pj_strcat2(&priority, "-VERS-SSL3.0:");
  1045. + pj_strcat2(&priority, "%LATEST_RECORD_VERSION");
  1046. +
  1047. + pj_strcat(&cipher_list, &priority);
  1048. + for (i = 0; i < ssock->param.ciphers_num; i++) {
  1049. + for (j = 0; ; j++) {
  1050. + pj_ssl_cipher c;
  1051. + const char *suite;
  1052. + unsigned char id[2];
  1053. + gnutls_protocol_t proto;
  1054. + gnutls_kx_algorithm_t kx;
  1055. + gnutls_mac_algorithm_t mac;
  1056. + gnutls_cipher_algorithm_t algo;
  1057. +
  1058. + suite = gnutls_cipher_suite_info(j, (unsigned char *)id,
  1059. + &kx, &algo, &mac, &proto);
  1060. + if (!suite)
  1061. + break;
  1062. +
  1063. + c = (pj_ssl_cipher) (pj_uint32_t) ((id[0] << 8) | id[1]);
  1064. + if (ssock->param.ciphers[i] == c) {
  1065. + char temp[256];
  1066. + pj_str_t cipher_entry;
  1067. +
  1068. + /* Protocol version */
  1069. + pj_strset(&cipher_entry, temp, 0);
  1070. + pj_strcat2(&cipher_entry, "VERS-");
  1071. + pj_strcat2(&cipher_entry, gnutls_protocol_get_name(proto));
  1072. + ret = tls_str_append_once(&cipher_list, &cipher_entry);
  1073. + if (ret != PJ_SUCCESS)
  1074. + return ret;
  1075. +
  1076. + /* Cipher */
  1077. + pj_strset(&cipher_entry, temp, 0);
  1078. + pj_strcat2(&cipher_entry, gnutls_cipher_get_name(algo));
  1079. + ret = tls_str_append_once(&cipher_list, &cipher_entry);
  1080. + if (ret != PJ_SUCCESS)
  1081. + return ret;
  1082. +
  1083. + /* Mac */
  1084. + pj_strset(&cipher_entry, temp, 0);
  1085. + pj_strcat2(&cipher_entry, gnutls_mac_get_name(mac));
  1086. + ret = tls_str_append_once(&cipher_list, &cipher_entry);
  1087. + if (ret != PJ_SUCCESS)
  1088. + return ret;
  1089. +
  1090. + /* Key exchange */
  1091. + pj_strset(&cipher_entry, temp, 0);
  1092. + pj_strcat2(&cipher_entry, gnutls_kx_get_name(kx));
  1093. + ret = tls_str_append_once(&cipher_list, &cipher_entry);
  1094. + if (ret != PJ_SUCCESS)
  1095. + return ret;
  1096. +
  1097. + /* Compression is always disabled */
  1098. + /* Signature is level-default */
  1099. + break;
  1100. + }
  1101. + }
  1102. + }
  1103. +
  1104. + /* Disable compression, it's a TLS-only extension after all */
  1105. + tls_str_append_once(&cipher_list, &compression);
  1106. +
  1107. + /* Server will be the one deciding which crypto to use */
  1108. + if (ssock->is_server) {
  1109. + if (cipher_list.slen + server.slen + 1 > sizeof(buf))
  1110. + return PJ_ETOOMANY;
  1111. + else
  1112. + pj_strcat(&cipher_list, &server);
  1113. + }
  1114. +
  1115. + /* End the string and print it */
  1116. + cipher_list.ptr[cipher_list.slen] = '\0';
  1117. + PJ_LOG(5, (ssock->pool->obj_name, "Priority string: %s", cipher_list.ptr));
  1118. +
  1119. + /* Set our priority string */
  1120. + ret = gnutls_priority_set_direct(ssock->session,
  1121. + cipher_list.ptr, &err);
  1122. + if (ret < 0) {
  1123. + tls_last_error = GNUTLS_E_INVALID_REQUEST;
  1124. + return PJ_EINVAL;
  1125. + }
  1126. +
  1127. + return PJ_SUCCESS;
  1128. +}
  1129. +
  1130. +
  1131. +/* Load root CA file or load the installed ones. */
  1132. +static pj_status_t tls_trust_set(pj_ssl_sock_t *ssock)
  1133. +{
  1134. + int ntrusts = 0;
  1135. + int err;
  1136. +
  1137. + err = gnutls_certificate_set_x509_system_trust(ssock->xcred);
  1138. + if (err > 0)
  1139. + ntrusts += err;
  1140. + err = gnutls_certificate_set_x509_trust_file(ssock->xcred,
  1141. + TRUST_STORE_FILE1,
  1142. + GNUTLS_X509_FMT_PEM);
  1143. + if (err > 0)
  1144. + ntrusts += err;
  1145. +
  1146. + err = gnutls_certificate_set_x509_trust_file(ssock->xcred,
  1147. + TRUST_STORE_FILE2,
  1148. + GNUTLS_X509_FMT_PEM);
  1149. + if (err > 0)
  1150. + ntrusts += err;
  1151. +
  1152. + if (ntrusts > 0)
  1153. + return PJ_SUCCESS;
  1154. + else if (!ntrusts)
  1155. + return PJ_ENOTFOUND;
  1156. + else
  1157. + return PJ_EINVAL;
  1158. +}
  1159. +
  1160. +#if GNUTLS_VERSION_NUMBER < 0x030306
  1161. +
  1162. +#ifdef _POSIX_PATH_MAX
  1163. +# define GNUTLS_PATH_MAX _POSIX_PATH_MAX
  1164. +#else
  1165. +# define GNUTLS_PATH_MAX 256
  1166. +#endif
  1167. +
  1168. +static
  1169. +int gnutls_certificate_set_x509_trust_dir(gnutls_certificate_credentials_t cred, const char *dirname, unsigned type)
  1170. +{
  1171. + DIR *dirp;
  1172. + struct dirent *d;
  1173. + int ret;
  1174. + int r = 0;
  1175. + char path[GNUTLS_PATH_MAX];
  1176. +#ifndef _WIN32
  1177. + struct dirent e;
  1178. +#endif
  1179. +
  1180. + dirp = opendir(dirname);
  1181. + if (dirp != NULL) {
  1182. + do {
  1183. +#ifdef _WIN32
  1184. + d = readdir(dirp);
  1185. + if (d != NULL) {
  1186. +#else
  1187. + ret = readdir_r(dirp, &e, &d);
  1188. + if (ret == 0 && d != NULL
  1189. +#ifdef _DIRENT_HAVE_D_TYPE
  1190. + && (d->d_type == DT_REG || d->d_type == DT_LNK || d->d_type == DT_UNKNOWN)
  1191. +#endif
  1192. + ) {
  1193. +#endif
  1194. + snprintf(path, sizeof(path), "%s/%s",
  1195. + dirname, d->d_name);
  1196. +
  1197. + ret = gnutls_certificate_set_x509_trust_file(cred, path, type);
  1198. + if (ret >= 0)
  1199. + r += ret;
  1200. + }
  1201. + }
  1202. + while (d != NULL);
  1203. + closedir(dirp);
  1204. + }
  1205. +
  1206. + return r;
  1207. +}
  1208. +
  1209. +#endif
  1210. +
  1211. +/* Create and initialize new GnuTLS context and instance */
  1212. +static pj_status_t tls_open(pj_ssl_sock_t *ssock)
  1213. +{
  1214. + pj_ssl_cert_t *cert;
  1215. + pj_status_t status;
  1216. + int ret;
  1217. +
  1218. + pj_assert(ssock);
  1219. +
  1220. + cert = ssock->cert;
  1221. +
  1222. + /* Even if reopening is harmless, having one instance only simplifies
  1223. + * deallocating it later on */
  1224. + if (!ssock->tls_init_count) {
  1225. + ssock->tls_init_count++;
  1226. + ret = tls_init();
  1227. + if (ret < 0)
  1228. + return ret;
  1229. + } else
  1230. + return PJ_SUCCESS;
  1231. +
  1232. + /* Start this socket session */
  1233. + ret = gnutls_init(&ssock->session, ssock->is_server ? GNUTLS_SERVER
  1234. + : GNUTLS_CLIENT);
  1235. + if (ret < 0)
  1236. + goto out;
  1237. +
  1238. + /* Set the ssock object to be retrieved by transport (send/recv) and by
  1239. + * user data from this session */
  1240. + gnutls_transport_set_ptr(ssock->session,
  1241. + (gnutls_transport_ptr_t) (uintptr_t) ssock);
  1242. + gnutls_session_set_ptr(ssock->session,
  1243. + (gnutls_transport_ptr_t) (uintptr_t) ssock);
  1244. +
  1245. + /* Initialize input circular buffer */
  1246. + status = circ_init(ssock->pool->factory, &ssock->circ_buf_input, 512);
  1247. + if (status != PJ_SUCCESS)
  1248. + return status;
  1249. +
  1250. + /* Initialize output circular buffer */
  1251. + status = circ_init(ssock->pool->factory, &ssock->circ_buf_output, 512);
  1252. + if (status != PJ_SUCCESS)
  1253. + return status;
  1254. +
  1255. + /* Set the callback that allows GnuTLS to PUSH and PULL data
  1256. + * TO and FROM the transport layer */
  1257. + gnutls_transport_set_push_function(ssock->session, tls_data_push);
  1258. + gnutls_transport_set_pull_function(ssock->session, tls_data_pull);
  1259. +
  1260. + /* Determine which cipher suite to support */
  1261. + status = tls_priorities_set(ssock);
  1262. + if (status != PJ_SUCCESS)
  1263. + return status;
  1264. +
  1265. + /* Allocate credentials for handshaking and transmission */
  1266. + ret = gnutls_certificate_allocate_credentials(&ssock->xcred);
  1267. + if (ret < 0)
  1268. + goto out;
  1269. + gnutls_certificate_set_verify_function(ssock->xcred, tls_cert_verify_cb);
  1270. +
  1271. + /* Load system trust file(s) */
  1272. + status = tls_trust_set(ssock);
  1273. + if (status != PJ_SUCCESS)
  1274. + return status;
  1275. +
  1276. + /* Load user-provided CA, certificate and key if available */
  1277. + if (cert) {
  1278. + /* Load CA if one is specified. */
  1279. + if (cert->CA_file.slen) {
  1280. + ret = gnutls_certificate_set_x509_trust_file(ssock->xcred,
  1281. + cert->CA_file.ptr,
  1282. + GNUTLS_X509_FMT_PEM);
  1283. + if (ret < 0)
  1284. + ret = gnutls_certificate_set_x509_trust_file(ssock->xcred,
  1285. + cert->CA_file.ptr,
  1286. + GNUTLS_X509_FMT_DER);
  1287. + if (ret < 0)
  1288. + goto out;
  1289. + }
  1290. + if (cert->CA_path.slen) {
  1291. + ret = gnutls_certificate_set_x509_trust_dir(ssock->xcred,
  1292. + cert->CA_path.ptr,
  1293. + GNUTLS_X509_FMT_PEM);
  1294. + if (ret < 0)
  1295. + ret = gnutls_certificate_set_x509_trust_dir(ssock->xcred,
  1296. + cert->CA_path.ptr,
  1297. + GNUTLS_X509_FMT_DER);
  1298. + if (ret < 0)
  1299. + goto out;
  1300. + }
  1301. +
  1302. + /* Load certificate, key and pass if one is specified */
  1303. + if (cert->cert_file.slen && cert->privkey_file.slen) {
  1304. + const char *prikey_file = cert->privkey_file.ptr;
  1305. + const char *prikey_pass = cert->privkey_pass.slen
  1306. + ? cert->privkey_pass.ptr
  1307. + : NULL;
  1308. + ret = gnutls_certificate_set_x509_key_file2(ssock->xcred,
  1309. + cert->cert_file.ptr,
  1310. + prikey_file,
  1311. + GNUTLS_X509_FMT_PEM,
  1312. + prikey_pass,
  1313. + 0);
  1314. + if (ret != GNUTLS_E_SUCCESS)
  1315. + ret = gnutls_certificate_set_x509_key_file2(ssock->xcred,
  1316. + cert->cert_file.ptr,
  1317. + prikey_file,
  1318. + GNUTLS_X509_FMT_DER,
  1319. + prikey_pass,
  1320. + 0);
  1321. + if (ret < 0)
  1322. + goto out;
  1323. + }
  1324. + }
  1325. +
  1326. + /* Require client certificate if asked */
  1327. + if (ssock->is_server && ssock->param.require_client_cert)
  1328. + gnutls_certificate_server_set_request(ssock->session,
  1329. + GNUTLS_CERT_REQUIRE);
  1330. +
  1331. + /* Finally set credentials for this session */
  1332. + ret = gnutls_credentials_set(ssock->session,
  1333. + GNUTLS_CRD_CERTIFICATE, ssock->xcred);
  1334. + if (ret < 0)
  1335. + goto out;
  1336. +
  1337. + ret = GNUTLS_E_SUCCESS;
  1338. +out:
  1339. + return tls_status_from_err(ssock, ret);
  1340. +}
  1341. +
  1342. +
  1343. +/* Destroy GnuTLS credentials and session. */
  1344. +static void tls_close(pj_ssl_sock_t *ssock)
  1345. +{
  1346. + if (ssock->session) {
  1347. + gnutls_bye(ssock->session, GNUTLS_SHUT_RDWR);
  1348. + gnutls_deinit(ssock->session);
  1349. + ssock->session = NULL;
  1350. + }
  1351. +
  1352. + if (ssock->xcred) {
  1353. + gnutls_certificate_free_credentials(ssock->xcred);
  1354. + ssock->xcred = NULL;
  1355. + }
  1356. +
  1357. + /* Free GnuTLS library */
  1358. + if (ssock->tls_init_count) {
  1359. + ssock->tls_init_count--;
  1360. + tls_deinit();
  1361. + }
  1362. +
  1363. + /* Destroy circular buffers */
  1364. + circ_deinit(&ssock->circ_buf_input);
  1365. + circ_deinit(&ssock->circ_buf_output);
  1366. +}
  1367. +
  1368. +
  1369. +/* Reset socket state. */
  1370. +static void tls_sock_reset(pj_ssl_sock_t *ssock)
  1371. +{
  1372. + ssock->connection_state = TLS_STATE_NULL;
  1373. +
  1374. + tls_close(ssock);
  1375. +
  1376. + if (ssock->asock) {
  1377. + pj_activesock_close(ssock->asock);
  1378. + ssock->asock = NULL;
  1379. + ssock->sock = PJ_INVALID_SOCKET;
  1380. + }
  1381. + if (ssock->sock != PJ_INVALID_SOCKET) {
  1382. + pj_sock_close(ssock->sock);
  1383. + ssock->sock = PJ_INVALID_SOCKET;
  1384. + }
  1385. +
  1386. + ssock->last_err = tls_last_error = GNUTLS_E_SUCCESS;
  1387. +}
  1388. +
  1389. +
  1390. +/* Get Common Name field string from a general name string */
  1391. +static void tls_cert_get_cn(const pj_str_t *gen_name, pj_str_t *cn)
  1392. +{
  1393. + pj_str_t CN_sign = {"CN=", 3};
  1394. + char *p, *q;
  1395. +
  1396. + pj_bzero(cn, sizeof(cn));
  1397. +
  1398. + p = pj_strstr(gen_name, &CN_sign);
  1399. + if (!p)
  1400. + return;
  1401. +
  1402. + p += 3; /* shift pointer to value part */
  1403. + pj_strset(cn, p, gen_name->slen - (p - gen_name->ptr));
  1404. + q = pj_strchr(cn, ',');
  1405. + if (q)
  1406. + cn->slen = q - p;
  1407. +}
  1408. +
  1409. +
  1410. +/* Get certificate info; in case the certificate info is already populated,
  1411. + * this function will check if the contents need updating by inspecting the
  1412. + * issuer and the serial number. */
  1413. +static void tls_cert_get_info(pj_pool_t *pool, pj_ssl_cert_info *ci, gnutls_x509_crt_t cert)
  1414. +{
  1415. + pj_bool_t update_needed;
  1416. + char buf[512] = { 0 };
  1417. + size_t bufsize = sizeof(buf);
  1418. + pj_uint8_t serial_no[64] = { 0 }; /* should be >= sizeof(ci->serial_no) */
  1419. + size_t serialsize = sizeof(serial_no);
  1420. + size_t len = sizeof(buf);
  1421. + int i, ret, seq = 0;
  1422. + pj_ssl_cert_name_type type;
  1423. +
  1424. + pj_assert(pool && ci && cert);
  1425. +
  1426. + /* Get issuer */
  1427. + gnutls_x509_crt_get_issuer_dn(cert, buf, &bufsize);
  1428. +
  1429. + /* Get serial no */
  1430. + gnutls_x509_crt_get_serial(cert, serial_no, &serialsize);
  1431. +
  1432. + /* Check if the contents need to be updated */
  1433. + update_needed = pj_strcmp2(&ci->issuer.info, buf) ||
  1434. + pj_memcmp(ci->serial_no, serial_no, serialsize);
  1435. + if (!update_needed)
  1436. + return;
  1437. +
  1438. + /* Update cert info */
  1439. +
  1440. + pj_bzero(ci, sizeof(pj_ssl_cert_info));
  1441. +
  1442. + /* Version */
  1443. + ci->version = gnutls_x509_crt_get_version(cert);
  1444. +
  1445. + /* Issuer */
  1446. + pj_strdup2(pool, &ci->issuer.info, buf);
  1447. + tls_cert_get_cn(&ci->issuer.info, &ci->issuer.cn);
  1448. +
  1449. + /* Serial number */
  1450. + pj_memcpy(ci->serial_no, serial_no, sizeof(ci->serial_no));
  1451. +
  1452. + /* Subject */
  1453. + bufsize = sizeof(buf);
  1454. + gnutls_x509_crt_get_dn(cert, buf, &bufsize);
  1455. + pj_strdup2(pool, &ci->subject.info, buf);
  1456. + tls_cert_get_cn(&ci->subject.info, &ci->subject.cn);
  1457. +
  1458. + /* Validity */
  1459. + ci->validity.end.sec = gnutls_x509_crt_get_expiration_time(cert);
  1460. + ci->validity.start.sec = gnutls_x509_crt_get_activation_time(cert);
  1461. + ci->validity.gmt = 0;
  1462. +
  1463. + /* Subject Alternative Name extension */
  1464. + if (ci->version >= 3) {
  1465. + char out[256] = { 0 };
  1466. + /* Get the number of all alternate names so that we can allocate
  1467. + * the correct number of bytes in subj_alt_name */
  1468. + while (gnutls_x509_crt_get_subject_alt_name(cert, seq, out, &len,
  1469. + NULL) != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
  1470. + seq++;
  1471. +
  1472. + ci->subj_alt_name.entry = pj_pool_calloc(pool, seq,
  1473. + sizeof(*ci->subj_alt_name.entry));
  1474. + if (!ci->subj_alt_name.entry) {
  1475. + tls_last_error = GNUTLS_E_MEMORY_ERROR;
  1476. + return;
  1477. + }
  1478. +
  1479. + /* Now populate the alternative names */
  1480. + for (i = 0; i < seq; i++) {
  1481. + len = sizeof(out) - 1;
  1482. + ret = gnutls_x509_crt_get_subject_alt_name(cert, i, out, &len, NULL);
  1483. + switch (ret) {
  1484. + case GNUTLS_SAN_IPADDRESS:
  1485. + type = PJ_SSL_CERT_NAME_IP;
  1486. + pj_inet_ntop2(len == sizeof(pj_in6_addr) ? pj_AF_INET6()
  1487. + : pj_AF_INET(),
  1488. + out, buf, sizeof(buf));
  1489. + break;
  1490. + case GNUTLS_SAN_URI:
  1491. + type = PJ_SSL_CERT_NAME_URI;
  1492. + break;
  1493. + case GNUTLS_SAN_RFC822NAME:
  1494. + type = PJ_SSL_CERT_NAME_RFC822;
  1495. + break;
  1496. + case GNUTLS_SAN_DNSNAME:
  1497. + type = PJ_SSL_CERT_NAME_DNS;
  1498. + break;
  1499. + default:
  1500. + type = PJ_SSL_CERT_NAME_UNKNOWN;
  1501. + break;
  1502. + }
  1503. +
  1504. + if (len && type != PJ_SSL_CERT_NAME_UNKNOWN) {
  1505. + ci->subj_alt_name.entry[ci->subj_alt_name.cnt].type = type;
  1506. + pj_strdup2(pool,
  1507. + &ci->subj_alt_name.entry[ci->subj_alt_name.cnt].name,
  1508. + type == PJ_SSL_CERT_NAME_IP ? buf : out);
  1509. + ci->subj_alt_name.cnt++;
  1510. + }
  1511. + }
  1512. + /* TODO: if no DNS alt. names were found, we could check against
  1513. + * the commonName as per RFC3280. */
  1514. + }
  1515. +}
  1516. +
  1517. +static void tls_cert_get_chain_raw(pj_pool_t *pool, pj_ssl_cert_info *ci, const gnutls_datum_t *certs, size_t certs_num)
  1518. +{
  1519. + size_t i=0;
  1520. + ci->raw_chain.cert_raw = pj_pool_calloc(pool, certs_num, sizeof(*ci->raw_chain.cert_raw));
  1521. + ci->raw_chain.cnt = certs_num;
  1522. + for (i=0; i < certs_num; ++i) {
  1523. + const pj_str_t crt_raw = {(const char*)certs[i].data, (pj_ssize_t)certs[i].size};
  1524. + pj_strdup(pool, ci->raw_chain.cert_raw+i, &crt_raw);
  1525. + }
  1526. +}
  1527. +
  1528. +/* Update local & remote certificates info. This function should be
  1529. + * called after handshake or renegotiation successfully completed. */
  1530. +static void tls_cert_update(pj_ssl_sock_t *ssock)
  1531. +{
  1532. + gnutls_x509_crt_t cert = NULL;
  1533. + const gnutls_datum_t *us;
  1534. + const gnutls_datum_t *certs;
  1535. + unsigned int certslen = 0;
  1536. + int ret = GNUTLS_CERT_INVALID;
  1537. +
  1538. + pj_assert(ssock->connection_state == TLS_STATE_ESTABLISHED);
  1539. +
  1540. + /* Get active local certificate */
  1541. + us = gnutls_certificate_get_ours(ssock->session);
  1542. + if (!us)
  1543. + goto us_out;
  1544. +
  1545. + ret = gnutls_x509_crt_init(&cert);
  1546. + if (ret < 0)
  1547. + goto us_out;
  1548. + ret = gnutls_x509_crt_import(cert, us, GNUTLS_X509_FMT_DER);
  1549. + if (ret < 0)
  1550. + ret = gnutls_x509_crt_import(cert, us, GNUTLS_X509_FMT_PEM);
  1551. + if (ret < 0)
  1552. + goto us_out;
  1553. +
  1554. + tls_cert_get_info(ssock->pool, &ssock->local_cert_info, cert);
  1555. + tls_cert_get_chain_raw(ssock->pool, &ssock->local_cert_info, us, 1);
  1556. +
  1557. +us_out:
  1558. + tls_last_error = ret;
  1559. + if (cert)
  1560. + gnutls_x509_crt_deinit(cert);
  1561. + else
  1562. + pj_bzero(&ssock->local_cert_info, sizeof(pj_ssl_cert_info));
  1563. +
  1564. + cert = NULL;
  1565. +
  1566. + /* Get active remote certificate */
  1567. + certs = gnutls_certificate_get_peers(ssock->session, &certslen);
  1568. + if (certs == NULL || certslen == 0)
  1569. + goto peer_out;
  1570. +
  1571. + ret = gnutls_x509_crt_init(&cert);
  1572. + if (ret < 0)
  1573. + goto peer_out;
  1574. +
  1575. + ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_PEM);
  1576. + if (ret < 0)
  1577. + ret = gnutls_x509_crt_import(cert, certs, GNUTLS_X509_FMT_DER);
  1578. + if (ret < 0)
  1579. + goto peer_out;
  1580. +
  1581. + tls_cert_get_info(ssock->pool, &ssock->remote_cert_info, cert);
  1582. + tls_cert_get_chain_raw(ssock->pool, &ssock->remote_cert_info, certs, certslen);
  1583. +
  1584. +peer_out:
  1585. + tls_last_error = ret;
  1586. + if (cert)
  1587. + gnutls_x509_crt_deinit(cert);
  1588. + else
  1589. + pj_bzero(&ssock->remote_cert_info, sizeof(pj_ssl_cert_info));
  1590. +}
  1591. +
  1592. +
  1593. +/* When handshake completed:
  1594. + * - notify application
  1595. + * - if handshake failed, reset SSL state
  1596. + * - return PJ_FALSE when SSL socket instance is destroyed by application. */
  1597. +static pj_bool_t on_handshake_complete(pj_ssl_sock_t *ssock,
  1598. + pj_status_t status)
  1599. +{
  1600. + pj_bool_t ret = PJ_TRUE;
  1601. +
  1602. + /* Cancel handshake timer */
  1603. + if (ssock->timer.id == TIMER_HANDSHAKE_TIMEOUT) {
  1604. + pj_timer_heap_cancel(ssock->param.timer_heap, &ssock->timer);
  1605. + ssock->timer.id = TIMER_NONE;
  1606. + }
  1607. +
  1608. + /* Update certificates info on successful handshake */
  1609. + if (status == PJ_SUCCESS)
  1610. + tls_cert_update(ssock);
  1611. +
  1612. + /* Accepting */
  1613. + if (ssock->is_server) {
  1614. + if (status != PJ_SUCCESS) {
  1615. + /* Handshake failed in accepting, destroy our self silently. */
  1616. +
  1617. + char errmsg[PJ_ERR_MSG_SIZE];
  1618. + char buf[PJ_INET6_ADDRSTRLEN + 10];
  1619. +
  1620. + pj_strerror(status, errmsg, sizeof(errmsg));
  1621. + PJ_LOG(3, (ssock->pool->obj_name,
  1622. + "Handshake failed in accepting %s: %s",
  1623. + pj_sockaddr_print(&ssock->rem_addr, buf, sizeof(buf), 3),
  1624. + errmsg));
  1625. +
  1626. + /* Workaround for ticket #985 */
  1627. +#if (defined(PJ_WIN32) && PJ_WIN32 != 0) || (defined(PJ_WIN64) && PJ_WIN64 != 0)
  1628. + if (ssock->param.timer_heap) {
  1629. + pj_time_val interval = {0, DELAYED_CLOSE_TIMEOUT};
  1630. +
  1631. + tls_sock_reset(ssock);
  1632. +
  1633. + ssock->timer.id = TIMER_CLOSE;
  1634. + pj_time_val_normalize(&interval);
  1635. + if (pj_timer_heap_schedule(ssock->param.timer_heap,
  1636. + &ssock->timer, &interval) != 0)
  1637. + {
  1638. + ssock->timer.id = TIMER_NONE;
  1639. + pj_ssl_sock_close(ssock);
  1640. + }
  1641. + } else
  1642. +#endif /* PJ_WIN32 */
  1643. + {
  1644. + pj_ssl_sock_close(ssock);
  1645. + }
  1646. +
  1647. + return PJ_FALSE;
  1648. + }
  1649. + /* Notify application the newly accepted SSL socket */
  1650. + if (ssock->param.cb.on_accept_complete)
  1651. + ret = (*ssock->param.cb.on_accept_complete)
  1652. + (ssock->parent, ssock, (pj_sockaddr_t*)&ssock->rem_addr,
  1653. + pj_sockaddr_get_len((pj_sockaddr_t*)&ssock->rem_addr));
  1654. +
  1655. + } else { /* Connecting */
  1656. + /* On failure, reset SSL socket state first, as app may try to
  1657. + * reconnect in the callback. */
  1658. + if (status != PJ_SUCCESS) {
  1659. + /* Server disconnected us, possibly due to negotiation failure */
  1660. + tls_sock_reset(ssock);
  1661. + }
  1662. + if (ssock->param.cb.on_connect_complete) {
  1663. +
  1664. + ret = (*ssock->param.cb.on_connect_complete)(ssock, status);
  1665. + }
  1666. + }
  1667. +
  1668. + return ret;
  1669. +}
  1670. +
  1671. +static write_data_t *alloc_send_data(pj_ssl_sock_t *ssock, pj_size_t len)
  1672. +{
  1673. + send_buf_t *send_buf = &ssock->send_buf;
  1674. + pj_size_t avail_len, skipped_len = 0;
  1675. + char *reg1, *reg2;
  1676. + pj_size_t reg1_len, reg2_len;
  1677. + write_data_t *p;
  1678. +
  1679. + /* Check buffer availability */
  1680. + avail_len = send_buf->max_len - send_buf->len;
  1681. + if (avail_len < len)
  1682. + return NULL;
  1683. +
  1684. + /* If buffer empty, reset start pointer and return it */
  1685. + if (send_buf->len == 0) {
  1686. + send_buf->start = send_buf->buf;
  1687. + send_buf->len = len;
  1688. + p = (write_data_t*)send_buf->start;
  1689. + goto init_send_data;
  1690. + }
  1691. +
  1692. + /* Free space may be wrapped/splitted into two regions, so let's
  1693. + * analyze them if any region can hold the write data. */
  1694. + reg1 = send_buf->start + send_buf->len;
  1695. + if (reg1 >= send_buf->buf + send_buf->max_len)
  1696. + reg1 -= send_buf->max_len;
  1697. + reg1_len = send_buf->max_len - send_buf->len;
  1698. + if (reg1 + reg1_len > send_buf->buf + send_buf->max_len) {
  1699. + reg1_len = send_buf->buf + send_buf->max_len - reg1;
  1700. + reg2 = send_buf->buf;
  1701. + reg2_len = send_buf->start - send_buf->buf;
  1702. + } else {
  1703. + reg2 = NULL;
  1704. + reg2_len = 0;
  1705. + }
  1706. +
  1707. + /* More buffer availability check, note that the write data must be in
  1708. + * a contigue buffer. */
  1709. + avail_len = PJ_MAX(reg1_len, reg2_len);
  1710. + if (avail_len < len)
  1711. + return NULL;
  1712. +
  1713. + /* Get the data slot */
  1714. + if (reg1_len >= len) {
  1715. + p = (write_data_t*)reg1;
  1716. + } else {
  1717. + p = (write_data_t*)reg2;
  1718. + skipped_len = reg1_len;
  1719. + }
  1720. +
  1721. + /* Update buffer length */
  1722. + send_buf->len += len + skipped_len;
  1723. +
  1724. +init_send_data:
  1725. + /* Init the new send data */
  1726. + pj_bzero(p, sizeof(*p));
  1727. + pj_list_init(p);
  1728. + pj_list_push_back(&ssock->send_pending, p);
  1729. +
  1730. + return p;
  1731. +}
  1732. +
  1733. +static void free_send_data(pj_ssl_sock_t *ssock, write_data_t *wdata)
  1734. +{
  1735. + send_buf_t *buf = &ssock->send_buf;
  1736. + write_data_t *spl = &ssock->send_pending;
  1737. +
  1738. + pj_assert(!pj_list_empty(&ssock->send_pending));
  1739. +
  1740. + /* Free slot from the buffer */
  1741. + if (spl->next == wdata && spl->prev == wdata) {
  1742. + /* This is the only data, reset the buffer */
  1743. + buf->start = buf->buf;
  1744. + buf->len = 0;
  1745. + } else if (spl->next == wdata) {
  1746. + /* This is the first data, shift start pointer of the buffer and
  1747. + * adjust the buffer length.
  1748. + */
  1749. + buf->start = (char*)wdata->next;
  1750. + if (wdata->next > wdata) {
  1751. + buf->len -= ((char*)wdata->next - buf->start);
  1752. + } else {
  1753. + /* Overlapped */
  1754. + pj_size_t right_len, left_len;
  1755. + right_len = buf->buf + buf->max_len - (char*)wdata;
  1756. + left_len = (char*)wdata->next - buf->buf;
  1757. + buf->len -= (right_len + left_len);
  1758. + }
  1759. + } else if (spl->prev == wdata) {
  1760. + /* This is the last data, just adjust the buffer length */
  1761. + if (wdata->prev < wdata) {
  1762. + pj_size_t jump_len;
  1763. + jump_len = (char*)wdata -
  1764. + ((char*)wdata->prev + wdata->prev->record_len);
  1765. + buf->len -= (wdata->record_len + jump_len);
  1766. + } else {
  1767. + /* Overlapped */
  1768. + pj_size_t right_len, left_len;
  1769. + right_len = buf->buf + buf->max_len -
  1770. + ((char*)wdata->prev + wdata->prev->record_len);
  1771. + left_len = (char*)wdata + wdata->record_len - buf->buf;
  1772. + buf->len -= (right_len + left_len);
  1773. + }
  1774. + }
  1775. + /* For data in the middle buffer, just do nothing on the buffer. The slot
  1776. + * will be freed later when freeing the first/last data. */
  1777. +
  1778. + /* Remove the data from send pending list */
  1779. + pj_list_erase(wdata);
  1780. +}
  1781. +
  1782. +#if 0
  1783. +/* Just for testing send buffer alloc/free */
  1784. +#include <pj/rand.h>
  1785. +pj_status_t pj_ssl_sock_ossl_test_send_buf(pj_pool_t *pool)
  1786. +{
  1787. + enum { MAX_CHUNK_NUM = 20 };
  1788. + unsigned chunk_size, chunk_cnt, i;
  1789. + write_data_t *wdata[MAX_CHUNK_NUM] = {0};
  1790. + pj_time_val now;
  1791. + pj_ssl_sock_t *ssock = NULL;
  1792. + pj_ssl_sock_param param;
  1793. + pj_status_t status;
  1794. +
  1795. + pj_gettimeofday(&now);
  1796. + pj_srand((unsigned)now.sec);
  1797. +
  1798. + pj_ssl_sock_param_default(&param);
  1799. + status = pj_ssl_sock_create(pool, &param, &ssock);
  1800. + if (status != PJ_SUCCESS) {
  1801. + return status;
  1802. + }
  1803. +
  1804. + if (ssock->send_buf.max_len == 0) {
  1805. + ssock->send_buf.buf = (char *)
  1806. + pj_pool_alloc(ssock->pool,
  1807. + ssock->param.send_buffer_size);
  1808. + ssock->send_buf.max_len = ssock->param.send_buffer_size;
  1809. + ssock->send_buf.start = ssock->send_buf.buf;
  1810. + ssock->send_buf.len = 0;
  1811. + }
  1812. +
  1813. + chunk_size = ssock->param.send_buffer_size / MAX_CHUNK_NUM / 2;
  1814. + chunk_cnt = 0;
  1815. + for (i = 0; i < MAX_CHUNK_NUM; i++) {
  1816. + wdata[i] = alloc_send_data(ssock, pj_rand() % chunk_size + 321);
  1817. + if (wdata[i])
  1818. + chunk_cnt++;
  1819. + else
  1820. + break;
  1821. + }
  1822. +
  1823. + while (chunk_cnt) {
  1824. + i = pj_rand() % MAX_CHUNK_NUM;
  1825. + if (wdata[i]) {
  1826. + free_send_data(ssock, wdata[i]);
  1827. + wdata[i] = NULL;
  1828. + chunk_cnt--;
  1829. + }
  1830. + }
  1831. +
  1832. + if (ssock->send_buf.len != 0)
  1833. + status = PJ_EBUG;
  1834. +
  1835. + pj_ssl_sock_close(ssock);
  1836. + return status;
  1837. +}
  1838. +#endif
  1839. +
  1840. +/* Flush write circular buffer to network socket. */
  1841. +static pj_status_t flush_circ_buf_output(pj_ssl_sock_t *ssock,
  1842. + pj_ioqueue_op_key_t *send_key,
  1843. + pj_size_t orig_len, unsigned flags)
  1844. +{
  1845. + pj_ssize_t len;
  1846. + write_data_t *wdata;
  1847. + pj_size_t needed_len;
  1848. + pj_status_t status;
  1849. +
  1850. + pj_lock_acquire(ssock->circ_buf_output_mutex);
  1851. +
  1852. + /* Check if there is data in the circular buffer, flush it if any */
  1853. + if (circ_empty(&ssock->circ_buf_output)) {
  1854. + pj_lock_release(ssock->circ_buf_output_mutex);
  1855. +
  1856. + return PJ_SUCCESS;
  1857. + }
  1858. +
  1859. + len = circ_size(&ssock->circ_buf_output);
  1860. +
  1861. + /* Calculate buffer size needed, and align it to 8 */
  1862. + needed_len = len + sizeof(write_data_t);
  1863. + needed_len = ((needed_len + 7) >> 3) << 3;
  1864. +
  1865. + /* Allocate buffer for send data */
  1866. + wdata = alloc_send_data(ssock, needed_len);
  1867. + if (wdata == NULL) {
  1868. + pj_lock_release(ssock->circ_buf_output_mutex);
  1869. + return PJ_ENOMEM;
  1870. + }
  1871. +
  1872. + /* Copy the data and set its properties into the send data */
  1873. + pj_ioqueue_op_key_init(&wdata->key, sizeof(pj_ioqueue_op_key_t));
  1874. + wdata->key.user_data = wdata;
  1875. + wdata->app_key = send_key;
  1876. + wdata->record_len = needed_len;
  1877. + wdata->data_len = len;
  1878. + wdata->plain_data_len = orig_len;
  1879. + wdata->flags = flags;
  1880. + circ_read(&ssock->circ_buf_output, (pj_uint8_t *)&wdata->data, len);
  1881. +
  1882. + /* Ticket #1573: Don't hold mutex while calling PJLIB socket send(). */
  1883. + pj_lock_release(ssock->circ_buf_output_mutex);
  1884. +
  1885. + /* Send it */
  1886. + if (ssock->param.sock_type == pj_SOCK_STREAM()) {
  1887. + status = pj_activesock_send(ssock->asock, &wdata->key,
  1888. + wdata->data.content, &len,
  1889. + flags);
  1890. + } else {
  1891. + status = pj_activesock_sendto(ssock->asock, &wdata->key,
  1892. + wdata->data.content, &len,
  1893. + flags,
  1894. + (pj_sockaddr_t*)&ssock->rem_addr,
  1895. + ssock->addr_len);
  1896. + }
  1897. +
  1898. + if (status != PJ_EPENDING) {
  1899. + /* When the sending is not pending, remove the wdata from send
  1900. + * pending list. */
  1901. + pj_lock_acquire(ssock->circ_buf_output_mutex);
  1902. + free_send_data(ssock, wdata);
  1903. + pj_lock_release(ssock->circ_buf_output_mutex);
  1904. + }
  1905. +
  1906. + return status;
  1907. +}
  1908. +
  1909. +static void on_timer(pj_timer_heap_t *th, struct pj_timer_entry *te)
  1910. +{
  1911. + pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)te->user_data;
  1912. + int timer_id = te->id;
  1913. +
  1914. + te->id = TIMER_NONE;
  1915. +
  1916. + PJ_UNUSED_ARG(th);
  1917. +
  1918. + switch (timer_id) {
  1919. + case TIMER_HANDSHAKE_TIMEOUT:
  1920. + PJ_LOG(1, (ssock->pool->obj_name, "TLS timeout after %d.%ds",
  1921. + ssock->param.timeout.sec, ssock->param.timeout.msec));
  1922. +
  1923. + on_handshake_complete(ssock, PJ_ETIMEDOUT);
  1924. + break;
  1925. + case TIMER_CLOSE:
  1926. + pj_ssl_sock_close(ssock);
  1927. + break;
  1928. + default:
  1929. + pj_assert(!"Unknown timer");
  1930. + break;
  1931. + }
  1932. +}
  1933. +
  1934. +
  1935. +/* Try to perform an asynchronous handshake */
  1936. +static pj_status_t tls_try_handshake(pj_ssl_sock_t *ssock)
  1937. +{
  1938. + int ret;
  1939. + pj_status_t status;
  1940. +
  1941. + /* Perform SSL handshake */
  1942. + ret = gnutls_handshake(ssock->session);
  1943. +
  1944. + status = flush_circ_buf_output(ssock, &ssock->handshake_op_key, 0, 0);
  1945. + if (status != PJ_SUCCESS)
  1946. + return status;
  1947. +
  1948. + if (ret == GNUTLS_E_SUCCESS) {
  1949. + /* System are GO */
  1950. + ssock->connection_state = TLS_STATE_ESTABLISHED;
  1951. + status = PJ_SUCCESS;
  1952. + } else if (!gnutls_error_is_fatal(ret)) {
  1953. + /* Non fatal error, retry later (busy or again) */
  1954. + status = PJ_EPENDING;
  1955. + } else {
  1956. + /* Fatal error invalidates session, no fallback */
  1957. + status = PJ_EINVAL;
  1958. + }
  1959. +
  1960. + tls_last_error = ret;
  1961. +
  1962. + return status;
  1963. +}
  1964. +
  1965. +
  1966. +/*
  1967. + *******************************************************************
  1968. + * Active socket callbacks.
  1969. + *******************************************************************
  1970. + */
  1971. +
  1972. +/* PJ_TRUE asks the socket to read more data, PJ_FALSE takes it off the queue */
  1973. +static pj_bool_t asock_on_data_read(pj_activesock_t *asock, void *data,
  1974. + pj_size_t size, pj_status_t status,
  1975. + pj_size_t *remainder)
  1976. +{
  1977. + pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)
  1978. + pj_activesock_get_user_data(asock);
  1979. +
  1980. + pj_size_t app_remainder = 0;
  1981. +
  1982. + if (data && size > 0) {
  1983. + /* Push data into input circular buffer (for GnuTLS) */
  1984. + pj_lock_acquire(ssock->circ_buf_input_mutex);
  1985. + circ_write(&ssock->circ_buf_input, data, size);
  1986. + pj_lock_release(ssock->circ_buf_input_mutex);
  1987. + }
  1988. +
  1989. + /* Check if SSL handshake hasn't finished yet */
  1990. + if (ssock->connection_state == TLS_STATE_HANDSHAKING) {
  1991. + pj_bool_t ret = PJ_TRUE;
  1992. +
  1993. + if (status == PJ_SUCCESS)
  1994. + status = tls_try_handshake(ssock);
  1995. +
  1996. + /* Not pending is either success or failed */
  1997. + if (status != PJ_EPENDING)
  1998. + ret = on_handshake_complete(ssock, status);
  1999. +
  2000. + return ret;
  2001. + }
  2002. +
  2003. + /* See if there is any decrypted data for the application */
  2004. + if (ssock->read_started) {
  2005. + do {
  2006. + /* Get read data structure at the end of the data */
  2007. + read_data_t *app_read_data = *(OFFSET_OF_READ_DATA_PTR(ssock, data));
  2008. + int app_data_size = (int)(ssock->read_size - app_read_data->len);
  2009. +
  2010. + /* Decrypt received data using GnuTLS (will read our input
  2011. + * circular buffer) */
  2012. + int decrypted_size = gnutls_record_recv(ssock->session,
  2013. + ((read_data_t *)app_read_data->data) +
  2014. + app_read_data->len,
  2015. + app_data_size);
  2016. +
  2017. + if (decrypted_size > 0 || status != PJ_SUCCESS) {
  2018. + if (ssock->param.cb.on_data_read) {
  2019. + pj_bool_t ret;
  2020. + app_remainder = 0;
  2021. +
  2022. + if (decrypted_size > 0)
  2023. + app_read_data->len += decrypted_size;
  2024. +
  2025. + ret = (*ssock->param.cb.on_data_read)(ssock,
  2026. + app_read_data->data,
  2027. + app_read_data->len,
  2028. + status,
  2029. + &app_remainder);
  2030. +
  2031. + if (!ret) {
  2032. + /* We've been destroyed */
  2033. + return PJ_FALSE;
  2034. + }
  2035. +
  2036. + /* Application may have left some data to be consumed
  2037. + * later as remainder */
  2038. + app_read_data->len = app_remainder;
  2039. + }
  2040. +
  2041. + /* Active socket signalled connection closed/error, this has
  2042. + * been signalled to the application along with any remaining
  2043. + * buffer. So, let's just reset SSL socket now. */
  2044. + if (status != PJ_SUCCESS) {
  2045. + tls_sock_reset(ssock);
  2046. + return PJ_FALSE;
  2047. + }
  2048. + } else if (decrypted_size == 0) {
  2049. + /* Nothing more to read */
  2050. +
  2051. + return PJ_TRUE;
  2052. + } else if (decrypted_size == GNUTLS_E_AGAIN ||
  2053. + decrypted_size == GNUTLS_E_INTERRUPTED) {
  2054. + return PJ_TRUE;
  2055. + } else if (decrypted_size == GNUTLS_E_REHANDSHAKE) {
  2056. + /* Seems like we are renegotiating */
  2057. + pj_status_t try_handshake_status = tls_try_handshake(ssock);
  2058. +
  2059. + /* Not pending is either success or failed */
  2060. + if (try_handshake_status != PJ_EPENDING) {
  2061. + if (!on_handshake_complete(ssock, try_handshake_status)) {
  2062. + return PJ_FALSE;
  2063. + }
  2064. + }
  2065. +
  2066. + if (try_handshake_status != PJ_SUCCESS &&
  2067. + try_handshake_status != PJ_EPENDING) {
  2068. + return PJ_FALSE;
  2069. + }
  2070. + } else if (!gnutls_error_is_fatal(decrypted_size)) {
  2071. + /* non-fatal error, let's just continue */
  2072. + } else {
  2073. + return PJ_FALSE;
  2074. + }
  2075. + } while (PJ_TRUE);
  2076. + }
  2077. +
  2078. + return PJ_TRUE;
  2079. +}
  2080. +
  2081. +
  2082. +/* Callback every time new data is available from the active socket */
  2083. +static pj_bool_t asock_on_data_sent(pj_activesock_t *asock,
  2084. + pj_ioqueue_op_key_t *send_key,
  2085. + pj_ssize_t sent)
  2086. +{
  2087. + pj_ssl_sock_t *ssock = (pj_ssl_sock_t *)pj_activesock_get_user_data(asock);
  2088. +
  2089. + PJ_UNUSED_ARG(send_key);
  2090. + PJ_UNUSED_ARG(sent);
  2091. +
  2092. + if (ssock->connection_state == TLS_STATE_HANDSHAKING) {
  2093. + /* Initial handshaking */
  2094. + pj_status_t status = tls_try_handshake(ssock);
  2095. +
  2096. + /* Not pending is either success or failed */
  2097. + if (status != PJ_EPENDING)
  2098. + return on_handshake_complete(ssock, status);
  2099. +
  2100. + } else if (send_key != &ssock->handshake_op_key) {
  2101. + /* Some data has been sent, notify application */
  2102. + write_data_t *wdata = (write_data_t*)send_key->user_data;
  2103. + if (ssock->param.cb.on_data_sent) {
  2104. + pj_bool_t ret;
  2105. + pj_ssize_t sent_len;
  2106. +
  2107. + sent_len = sent > 0 ? wdata->plain_data_len : sent;
  2108. +
  2109. + ret = (*ssock->param.cb.on_data_sent)(ssock, wdata->app_key,
  2110. + sent_len);
  2111. + if (!ret) {
  2112. + /* We've been destroyed */
  2113. + return PJ_FALSE;
  2114. + }
  2115. + }
  2116. +
  2117. + /* Update write buffer state */
  2118. + pj_lock_acquire(ssock->circ_buf_output_mutex);
  2119. + free_send_data(ssock, wdata);
  2120. + pj_lock_release(ssock->circ_buf_output_mutex);
  2121. + } else {
  2122. + /* SSL re-negotiation is on-progress, just do nothing */
  2123. + /* FIXME: check if this is valid for GnuTLS too */
  2124. + }
  2125. +
  2126. + return PJ_TRUE;
  2127. +}
  2128. +
  2129. +
  2130. +/* Callback every time a new connection has been accepted (server) */
  2131. +static pj_bool_t asock_on_accept_complete(pj_activesock_t *asock,
  2132. + pj_sock_t newsock,
  2133. + const pj_sockaddr_t *src_addr,
  2134. + int src_addr_len)
  2135. +{
  2136. + pj_ssl_sock_t *ssock_parent = (pj_ssl_sock_t *)
  2137. + pj_activesock_get_user_data(asock);
  2138. +
  2139. + pj_ssl_sock_t *ssock;
  2140. + pj_activesock_cb asock_cb;
  2141. + pj_activesock_cfg asock_cfg;
  2142. + unsigned int i;
  2143. + pj_status_t status;
  2144. +
  2145. + PJ_UNUSED_ARG(src_addr_len);
  2146. +
  2147. + /* Create new SSL socket instance */
  2148. + status = pj_ssl_sock_create(ssock_parent->pool, &ssock_parent->newsock_param,
  2149. + &ssock);
  2150. + if (status != PJ_SUCCESS)
  2151. + goto on_return;
  2152. +
  2153. + /* Update new SSL socket attributes */
  2154. + ssock->sock = newsock;
  2155. + ssock->parent = ssock_parent;
  2156. + ssock->is_server = PJ_TRUE;
  2157. + if (ssock_parent->cert) {
  2158. + status = pj_ssl_sock_set_certificate(ssock, ssock->pool,
  2159. + ssock_parent->cert);
  2160. + if (status != PJ_SUCCESS)
  2161. + goto on_return;
  2162. + }
  2163. +
  2164. + /* Apply QoS, if specified */
  2165. + status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
  2166. + &ssock->param.qos_params, 1,
  2167. + ssock->pool->obj_name, NULL);
  2168. + if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
  2169. + goto on_return;
  2170. +
  2171. + /* Update local address */
  2172. + ssock->addr_len = src_addr_len;
  2173. + status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
  2174. + &ssock->addr_len);
  2175. + if (status != PJ_SUCCESS) {
  2176. + /* This fails on few envs, e.g: win IOCP, just tolerate this and
  2177. + * use parent local address instead.
  2178. + */
  2179. + pj_sockaddr_cp(&ssock->local_addr, &ssock_parent->local_addr);
  2180. + }
  2181. +
  2182. + /* Set remote address */
  2183. + pj_sockaddr_cp(&ssock->rem_addr, src_addr);
  2184. +
  2185. + /* Create SSL context */
  2186. + status = tls_open(ssock);
  2187. + if (status != PJ_SUCCESS)
  2188. + goto on_return;
  2189. +
  2190. + /* Prepare read buffer */
  2191. + ssock->asock_rbuf = (void **)pj_pool_calloc(ssock->pool,
  2192. + ssock->param.async_cnt,
  2193. + sizeof(void*));
  2194. + if (!ssock->asock_rbuf)
  2195. + return PJ_ENOMEM;
  2196. +
  2197. + for (i = 0; i < ssock->param.async_cnt; ++i) {
  2198. + ssock->asock_rbuf[i] = (void *)pj_pool_alloc(
  2199. + ssock->pool,
  2200. + ssock->param.read_buffer_size +
  2201. + sizeof(read_data_t*));
  2202. + if (!ssock->asock_rbuf[i])
  2203. + return PJ_ENOMEM;
  2204. + }
  2205. +
  2206. + /* Create active socket */
  2207. + pj_activesock_cfg_default(&asock_cfg);
  2208. + asock_cfg.async_cnt = ssock->param.async_cnt;
  2209. + asock_cfg.concurrency = ssock->param.concurrency;
  2210. + asock_cfg.whole_data = PJ_TRUE;
  2211. +
  2212. + pj_bzero(&asock_cb, sizeof(asock_cb));
  2213. + asock_cb.on_data_read = asock_on_data_read;
  2214. + asock_cb.on_data_sent = asock_on_data_sent;
  2215. +
  2216. + status = pj_activesock_create(ssock->pool,
  2217. + ssock->sock,
  2218. + ssock->param.sock_type,
  2219. + &asock_cfg,
  2220. + ssock->param.ioqueue,
  2221. + &asock_cb,
  2222. + ssock,
  2223. + &ssock->asock);
  2224. +
  2225. + if (status != PJ_SUCCESS)
  2226. + goto on_return;
  2227. +
  2228. + /* Start reading */
  2229. + status = pj_activesock_start_read2(ssock->asock, ssock->pool,
  2230. + (unsigned)ssock->param.read_buffer_size,
  2231. + ssock->asock_rbuf,
  2232. + PJ_IOQUEUE_ALWAYS_ASYNC);
  2233. + if (status != PJ_SUCCESS)
  2234. + goto on_return;
  2235. +
  2236. + /* Prepare write/send state */
  2237. + pj_assert(ssock->send_buf.max_len == 0);
  2238. + ssock->send_buf.buf = (char *)pj_pool_alloc(ssock->pool,
  2239. + ssock->param.send_buffer_size);
  2240. + if (!ssock->send_buf.buf)
  2241. + return PJ_ENOMEM;
  2242. +
  2243. + ssock->send_buf.max_len = ssock->param.send_buffer_size;
  2244. + ssock->send_buf.start = ssock->send_buf.buf;
  2245. + ssock->send_buf.len = 0;
  2246. +
  2247. + /* Start handshake timer */
  2248. + if (ssock->param.timer_heap &&
  2249. + (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0)) {
  2250. + pj_assert(ssock->timer.id == TIMER_NONE);
  2251. + ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
  2252. + status = pj_timer_heap_schedule(ssock->param.timer_heap,
  2253. + &ssock->timer,
  2254. + &ssock->param.timeout);
  2255. + if (status != PJ_SUCCESS)
  2256. + ssock->timer.id = TIMER_NONE;
  2257. + }
  2258. +
  2259. + /* Start SSL handshake */
  2260. + ssock->connection_state = TLS_STATE_HANDSHAKING;
  2261. +
  2262. + status = tls_try_handshake(ssock);
  2263. +
  2264. +on_return:
  2265. + if (ssock && status != PJ_EPENDING)
  2266. + on_handshake_complete(ssock, status);
  2267. +
  2268. + /* Must return PJ_TRUE whatever happened, as active socket must
  2269. + * continue listening.
  2270. + */
  2271. + return PJ_TRUE;
  2272. +}
  2273. +
  2274. +
  2275. +/* Callback every time a new connection has been completed (client) */
  2276. +static pj_bool_t asock_on_connect_complete (pj_activesock_t *asock,
  2277. + pj_status_t status)
  2278. +{
  2279. + pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)
  2280. + pj_activesock_get_user_data(asock);
  2281. +
  2282. + unsigned int i;
  2283. + int ret;
  2284. +
  2285. + if (status != PJ_SUCCESS)
  2286. + goto on_return;
  2287. +
  2288. + /* Update local address */
  2289. + ssock->addr_len = sizeof(pj_sockaddr);
  2290. + status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
  2291. + &ssock->addr_len);
  2292. + if (status != PJ_SUCCESS)
  2293. + goto on_return;
  2294. +
  2295. + /* Create SSL context */
  2296. + status = tls_open(ssock);
  2297. + if (status != PJ_SUCCESS)
  2298. + goto on_return;
  2299. +
  2300. + /* Prepare read buffer */
  2301. + ssock->asock_rbuf = (void **)pj_pool_calloc(ssock->pool,
  2302. + ssock->param.async_cnt,
  2303. + sizeof(void *));
  2304. + if (!ssock->asock_rbuf)
  2305. + return PJ_ENOMEM;
  2306. +
  2307. + for (i = 0; i < ssock->param.async_cnt; ++i) {
  2308. + ssock->asock_rbuf[i] = (void *)pj_pool_alloc(
  2309. + ssock->pool,
  2310. + ssock->param.read_buffer_size +
  2311. + sizeof(read_data_t *));
  2312. + if (!ssock->asock_rbuf[i])
  2313. + return PJ_ENOMEM;
  2314. + }
  2315. +
  2316. + /* Start read */
  2317. + status = pj_activesock_start_read2(ssock->asock, ssock->pool,
  2318. + (unsigned) ssock->param.read_buffer_size,
  2319. + ssock->asock_rbuf,
  2320. + PJ_IOQUEUE_ALWAYS_ASYNC);
  2321. + if (status != PJ_SUCCESS)
  2322. + goto on_return;
  2323. +
  2324. + /* Prepare write/send state */
  2325. + pj_assert(ssock->send_buf.max_len == 0);
  2326. + ssock->send_buf.buf = (char *)pj_pool_alloc(ssock->pool,
  2327. + ssock->param.send_buffer_size);
  2328. + if (!ssock->send_buf.buf)
  2329. + return PJ_ENOMEM;
  2330. +
  2331. + ssock->send_buf.max_len = ssock->param.send_buffer_size;
  2332. + ssock->send_buf.start = ssock->send_buf.buf;
  2333. + ssock->send_buf.len = 0;
  2334. +
  2335. + /* Set server name to connect */
  2336. + if (ssock->param.server_name.slen) {
  2337. + /* Server name is null terminated already */
  2338. + ret = gnutls_server_name_set(ssock->session, GNUTLS_NAME_DNS,
  2339. + ssock->param.server_name.ptr,
  2340. + ssock->param.server_name.slen);
  2341. + if (ret < 0) {
  2342. + PJ_LOG(3, (ssock->pool->obj_name,
  2343. + "gnutls_server_name_set() failed: %s",
  2344. + gnutls_strerror(ret)));
  2345. + }
  2346. + }
  2347. +
  2348. + /* Start handshake */
  2349. + ssock->connection_state = TLS_STATE_HANDSHAKING;
  2350. +
  2351. + status = tls_try_handshake(ssock);
  2352. + if (status != PJ_EPENDING)
  2353. + goto on_return;
  2354. +
  2355. + return PJ_TRUE;
  2356. +
  2357. +on_return:
  2358. + return on_handshake_complete(ssock, status);
  2359. +}
  2360. +
  2361. +static void tls_ciphers_fill(void)
  2362. +{
  2363. + if (!tls_available_ciphers) {
  2364. + tls_init();
  2365. + tls_deinit();
  2366. + }
  2367. +}
  2368. +
  2369. +/*
  2370. + *******************************************************************
  2371. + * API
  2372. + *******************************************************************
  2373. + */
  2374. +
  2375. +/* Load credentials from files. */
  2376. +PJ_DEF(pj_status_t) pj_ssl_cert_load_from_files(pj_pool_t *pool,
  2377. + const pj_str_t *CA_file,
  2378. + const pj_str_t *cert_file,
  2379. + const pj_str_t *privkey_file,
  2380. + const pj_str_t *privkey_pass,
  2381. + pj_ssl_cert_t **p_cert)
  2382. +{
  2383. + return pj_ssl_cert_load_from_files2(pool, CA_file, NULL, cert_file,
  2384. + privkey_file, privkey_pass, p_cert);
  2385. +}
  2386. +
  2387. +/* Load credentials from files. */
  2388. +PJ_DECL(pj_status_t) pj_ssl_cert_load_from_files2(
  2389. + pj_pool_t *pool,
  2390. + const pj_str_t *CA_file,
  2391. + const pj_str_t *CA_path,
  2392. + const pj_str_t *cert_file,
  2393. + const pj_str_t *privkey_file,
  2394. + const pj_str_t *privkey_pass,
  2395. + pj_ssl_cert_t **p_cert)
  2396. +{
  2397. + pj_ssl_cert_t *cert;
  2398. +
  2399. + PJ_ASSERT_RETURN(pool && (CA_file || CA_path) && cert_file &&
  2400. + privkey_file,
  2401. + PJ_EINVAL);
  2402. +
  2403. + cert = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
  2404. + if (CA_file) {
  2405. + pj_strdup_with_null(pool, &cert->CA_file, CA_file);
  2406. + }
  2407. + if (CA_path) {
  2408. + pj_strdup_with_null(pool, &cert->CA_path, CA_path);
  2409. + }
  2410. + pj_strdup_with_null(pool, &cert->cert_file, cert_file);
  2411. + pj_strdup_with_null(pool, &cert->privkey_file, privkey_file);
  2412. + pj_strdup_with_null(pool, &cert->privkey_pass, privkey_pass);
  2413. +
  2414. + *p_cert = cert;
  2415. +
  2416. + return PJ_SUCCESS;
  2417. +}
  2418. +
  2419. +/* Store credentials. */
  2420. +PJ_DECL(pj_status_t) pj_ssl_sock_set_certificate(pj_ssl_sock_t *ssock,
  2421. + pj_pool_t *pool,
  2422. + const pj_ssl_cert_t *cert)
  2423. +{
  2424. + pj_ssl_cert_t *cert_;
  2425. +
  2426. + PJ_ASSERT_RETURN(ssock && pool && cert, PJ_EINVAL);
  2427. +
  2428. + cert_ = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
  2429. + pj_memcpy(cert_, cert, sizeof(cert));
  2430. + pj_strdup_with_null(pool, &cert_->CA_file, &cert->CA_file);
  2431. + pj_strdup_with_null(pool, &cert_->CA_path, &cert->CA_path);
  2432. + pj_strdup_with_null(pool, &cert_->cert_file, &cert->cert_file);
  2433. + pj_strdup_with_null(pool, &cert_->privkey_file, &cert->privkey_file);
  2434. + pj_strdup_with_null(pool, &cert_->privkey_pass, &cert->privkey_pass);
  2435. +
  2436. + ssock->cert = cert_;
  2437. +
  2438. + return PJ_SUCCESS;
  2439. +}
  2440. +
  2441. +
  2442. +/* Get available ciphers. */
  2443. +PJ_DEF(pj_status_t) pj_ssl_cipher_get_availables(pj_ssl_cipher ciphers[],
  2444. + unsigned *cipher_num)
  2445. +{
  2446. + unsigned int i;
  2447. +
  2448. + PJ_ASSERT_RETURN(ciphers && cipher_num, PJ_EINVAL);
  2449. +
  2450. + tls_ciphers_fill();
  2451. +
  2452. + if (!tls_available_ciphers) {
  2453. + *cipher_num = 0;
  2454. + return PJ_ENOTFOUND;
  2455. + }
  2456. +
  2457. + *cipher_num = PJ_MIN(*cipher_num, tls_available_ciphers);
  2458. +
  2459. + for (i = 0; i < *cipher_num; ++i)
  2460. + ciphers[i] = tls_ciphers[i].id;
  2461. +
  2462. + return PJ_SUCCESS;
  2463. +}
  2464. +
  2465. +
  2466. +/* Get cipher name string. */
  2467. +PJ_DEF(const char *)pj_ssl_cipher_name(pj_ssl_cipher cipher)
  2468. +{
  2469. + unsigned int i;
  2470. +
  2471. + tls_ciphers_fill();
  2472. +
  2473. + for (i = 0; i < tls_available_ciphers; ++i) {
  2474. + if (cipher == tls_ciphers[i].id)
  2475. + return tls_ciphers[i].name;
  2476. + }
  2477. +
  2478. + return NULL;
  2479. +}
  2480. +
  2481. +
  2482. +/* Get cipher identifier. */
  2483. +PJ_DEF(pj_ssl_cipher) pj_ssl_cipher_id(const char *cipher_name)
  2484. +{
  2485. + unsigned int i;
  2486. +
  2487. + tls_ciphers_fill();
  2488. +
  2489. + for (i = 0; i < tls_available_ciphers; ++i) {
  2490. + if (!pj_ansi_stricmp(tls_ciphers[i].name, cipher_name))
  2491. + return tls_ciphers[i].id;
  2492. + }
  2493. +
  2494. + return PJ_TLS_UNKNOWN_CIPHER;
  2495. +}
  2496. +
  2497. +
  2498. +/* Check if the specified cipher is supported by the TLS backend. */
  2499. +PJ_DEF(pj_bool_t) pj_ssl_cipher_is_supported(pj_ssl_cipher cipher)
  2500. +{
  2501. + unsigned int i;
  2502. +
  2503. + tls_ciphers_fill();
  2504. +
  2505. + for (i = 0; i < tls_available_ciphers; ++i) {
  2506. + if (cipher == tls_ciphers[i].id)
  2507. + return PJ_TRUE;
  2508. + }
  2509. +
  2510. + return PJ_FALSE;
  2511. +}
  2512. +
  2513. +/* Create SSL socket instance. */
  2514. +PJ_DEF(pj_status_t) pj_ssl_sock_create(pj_pool_t *pool,
  2515. + const pj_ssl_sock_param *param,
  2516. + pj_ssl_sock_t **p_ssock)
  2517. +{
  2518. + pj_ssl_sock_t *ssock;
  2519. + pj_status_t status;
  2520. +
  2521. + PJ_ASSERT_RETURN(pool && param && p_ssock, PJ_EINVAL);
  2522. + PJ_ASSERT_RETURN(param->sock_type == pj_SOCK_STREAM(), PJ_ENOTSUP);
  2523. +
  2524. + pool = pj_pool_create(pool->factory, "tls%p", 512, 512, NULL);
  2525. +
  2526. + /* Create secure socket */
  2527. + ssock = PJ_POOL_ZALLOC_T(pool, pj_ssl_sock_t);
  2528. + ssock->pool = pool;
  2529. + ssock->sock = PJ_INVALID_SOCKET;
  2530. + ssock->connection_state = TLS_STATE_NULL;
  2531. + pj_list_init(&ssock->write_pending);
  2532. + pj_list_init(&ssock->write_pending_empty);
  2533. + pj_list_init(&ssock->send_pending);
  2534. + pj_timer_entry_init(&ssock->timer, 0, ssock, &on_timer);
  2535. + pj_ioqueue_op_key_init(&ssock->handshake_op_key,
  2536. + sizeof(pj_ioqueue_op_key_t));
  2537. +
  2538. + /* Create secure socket mutex */
  2539. + status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
  2540. + &ssock->circ_buf_output_mutex);
  2541. + if (status != PJ_SUCCESS)
  2542. + return status;
  2543. +
  2544. + /* Create input circular buffer mutex */
  2545. + status = pj_lock_create_simple_mutex(pool, pool->obj_name,
  2546. + &ssock->circ_buf_input_mutex);
  2547. + if (status != PJ_SUCCESS)
  2548. + return status;
  2549. +
  2550. + /* Create output circular buffer mutex */
  2551. + status = pj_lock_create_simple_mutex(pool, pool->obj_name,
  2552. + &ssock->circ_buf_output_mutex);
  2553. + if (status != PJ_SUCCESS)
  2554. + return status;
  2555. +
  2556. + /* Init secure socket param */
  2557. + ssock->param = *param;
  2558. + ssock->param.read_buffer_size = ((ssock->param.read_buffer_size + 7) >> 3) << 3;
  2559. +
  2560. + if (param->ciphers_num > 0) {
  2561. + unsigned int i;
  2562. + ssock->param.ciphers = (pj_ssl_cipher *)
  2563. + pj_pool_calloc(pool, param->ciphers_num,
  2564. + sizeof(pj_ssl_cipher));
  2565. + if (!ssock->param.ciphers)
  2566. + return PJ_ENOMEM;
  2567. +
  2568. + for (i = 0; i < param->ciphers_num; ++i)
  2569. + ssock->param.ciphers[i] = param->ciphers[i];
  2570. + }
  2571. +
  2572. + /* Server name must be null-terminated */
  2573. + pj_strdup_with_null(pool, &ssock->param.server_name, &param->server_name);
  2574. +
  2575. + /* Finally */
  2576. + *p_ssock = ssock;
  2577. +
  2578. + return PJ_SUCCESS;
  2579. +}
  2580. +
  2581. +
  2582. +/*
  2583. + * Close the secure socket. This will unregister the socket from the
  2584. + * ioqueue and ultimately close the socket.
  2585. + */
  2586. +PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
  2587. +{
  2588. + pj_pool_t *pool;
  2589. +
  2590. + PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
  2591. +
  2592. + if (!ssock->pool)
  2593. + return PJ_SUCCESS;
  2594. +
  2595. + if (ssock->timer.id != TIMER_NONE) {
  2596. + pj_timer_heap_cancel(ssock->param.timer_heap, &ssock->timer);
  2597. + ssock->timer.id = TIMER_NONE;
  2598. + }
  2599. +
  2600. + tls_sock_reset(ssock);
  2601. +
  2602. + pj_lock_destroy(ssock->circ_buf_output_mutex);
  2603. + pj_lock_destroy(ssock->circ_buf_input_mutex);
  2604. +
  2605. + pool = ssock->pool;
  2606. + ssock->pool = NULL;
  2607. + if (pool)
  2608. + pj_pool_release(pool);
  2609. +
  2610. + return PJ_SUCCESS;
  2611. +}
  2612. +
  2613. +
  2614. +/* Associate arbitrary data with the secure socket. */
  2615. +PJ_DEF(pj_status_t) pj_ssl_sock_set_user_data(pj_ssl_sock_t *ssock,
  2616. + void *user_data)
  2617. +{
  2618. + PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
  2619. +
  2620. + ssock->param.user_data = user_data;
  2621. + return PJ_SUCCESS;
  2622. +}
  2623. +
  2624. +
  2625. +/* Retrieve the user data previously associated with this secure socket. */
  2626. +PJ_DEF(void *)pj_ssl_sock_get_user_data(pj_ssl_sock_t *ssock)
  2627. +{
  2628. + PJ_ASSERT_RETURN(ssock, NULL);
  2629. +
  2630. + return ssock->param.user_data;
  2631. +}
  2632. +
  2633. +
  2634. +/* Retrieve the local address and port used by specified SSL socket. */
  2635. +PJ_DEF(pj_status_t) pj_ssl_sock_get_info (pj_ssl_sock_t *ssock,
  2636. + pj_ssl_sock_info *info)
  2637. +{
  2638. + pj_bzero(info, sizeof(*info));
  2639. +
  2640. + /* Established flag */
  2641. + info->established = (ssock->connection_state == TLS_STATE_ESTABLISHED);
  2642. +
  2643. + /* Protocol */
  2644. + info->proto = ssock->param.proto;
  2645. +
  2646. + /* Local address */
  2647. + pj_sockaddr_cp(&info->local_addr, &ssock->local_addr);
  2648. +
  2649. + if (info->established) {
  2650. + int i;
  2651. + gnutls_cipher_algorithm_t lookup;
  2652. + gnutls_cipher_algorithm_t cipher;
  2653. +
  2654. + /* Current cipher */
  2655. + cipher = gnutls_cipher_get(ssock->session);
  2656. + for (i = 0; ; i++) {
  2657. + unsigned char id[2];
  2658. + const char *suite = gnutls_cipher_suite_info(i, (unsigned char *)id,
  2659. + NULL, &lookup, NULL,
  2660. + NULL);
  2661. + if (suite) {
  2662. + if (lookup == cipher) {
  2663. + info->cipher = (pj_uint32_t) ((id[0] << 8) | id[1]);
  2664. + break;
  2665. + }
  2666. + } else
  2667. + break;
  2668. + }
  2669. +
  2670. + /* Remote address */
  2671. + pj_sockaddr_cp(&info->remote_addr, &ssock->rem_addr);
  2672. +
  2673. + /* Certificates info */
  2674. + info->local_cert_info = &ssock->local_cert_info;
  2675. + info->remote_cert_info = &ssock->remote_cert_info;
  2676. +
  2677. + /* Verification status */
  2678. + info->verify_status = ssock->verify_status;
  2679. + }
  2680. +
  2681. + /* Last known GnuTLS error code */
  2682. + info->last_native_err = ssock->last_err;
  2683. +
  2684. + return PJ_SUCCESS;
  2685. +}
  2686. +
  2687. +
  2688. +/* Starts read operation on this secure socket. */
  2689. +PJ_DEF(pj_status_t) pj_ssl_sock_start_read(pj_ssl_sock_t *ssock,
  2690. + pj_pool_t *pool,
  2691. + unsigned buff_size,
  2692. + pj_uint32_t flags)
  2693. +{
  2694. + void **readbuf;
  2695. + unsigned int i;
  2696. +
  2697. + PJ_ASSERT_RETURN(ssock && pool && buff_size, PJ_EINVAL);
  2698. + PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
  2699. + PJ_EINVALIDOP);
  2700. +
  2701. + readbuf = (void**) pj_pool_calloc(pool, ssock->param.async_cnt,
  2702. + sizeof(void *));
  2703. + if (!readbuf)
  2704. + return PJ_ENOMEM;
  2705. +
  2706. + for (i = 0; i < ssock->param.async_cnt; ++i) {
  2707. + readbuf[i] = pj_pool_alloc(pool, buff_size);
  2708. + if (!readbuf[i])
  2709. + return PJ_ENOMEM;
  2710. + }
  2711. +
  2712. + return pj_ssl_sock_start_read2(ssock, pool, buff_size, readbuf, flags);
  2713. +}
  2714. +
  2715. +
  2716. +/*
  2717. + * Same as #pj_ssl_sock_start_read(), except that the application
  2718. + * supplies the buffers for the read operation so that the acive socket
  2719. + * does not have to allocate the buffers.
  2720. + */
  2721. +PJ_DEF(pj_status_t) pj_ssl_sock_start_read2 (pj_ssl_sock_t *ssock,
  2722. + pj_pool_t *pool,
  2723. + unsigned buff_size,
  2724. + void *readbuf[],
  2725. + pj_uint32_t flags)
  2726. +{
  2727. + unsigned int i;
  2728. +
  2729. + PJ_ASSERT_RETURN(ssock && pool && buff_size && readbuf, PJ_EINVAL);
  2730. + PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
  2731. + PJ_EINVALIDOP);
  2732. +
  2733. + /* Create SSL socket read buffer */
  2734. + ssock->ssock_rbuf = (read_data_t*)pj_pool_calloc(pool,
  2735. + ssock->param.async_cnt,
  2736. + sizeof(read_data_t));
  2737. + if (!ssock->ssock_rbuf)
  2738. + return PJ_ENOMEM;
  2739. +
  2740. + /* Store SSL socket read buffer pointer in the activesock read buffer */
  2741. + for (i = 0; i < ssock->param.async_cnt; ++i) {
  2742. + read_data_t **p_ssock_rbuf =
  2743. + OFFSET_OF_READ_DATA_PTR(ssock, ssock->asock_rbuf[i]);
  2744. +
  2745. + ssock->ssock_rbuf[i].data = readbuf[i];
  2746. + ssock->ssock_rbuf[i].len = 0;
  2747. +
  2748. + *p_ssock_rbuf = &ssock->ssock_rbuf[i];
  2749. + }
  2750. +
  2751. + ssock->read_size = buff_size;
  2752. + ssock->read_started = PJ_TRUE;
  2753. + ssock->read_flags = flags;
  2754. +
  2755. + return PJ_SUCCESS;
  2756. +}
  2757. +
  2758. +
  2759. +/*
  2760. + * Same as pj_ssl_sock_start_read(), except that this function is used
  2761. + * only for datagram sockets, and it will trigger \a on_data_recvfrom()
  2762. + * callback instead.
  2763. + */
  2764. +PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom (pj_ssl_sock_t *ssock,
  2765. + pj_pool_t *pool,
  2766. + unsigned buff_size,
  2767. + pj_uint32_t flags)
  2768. +{
  2769. + PJ_UNUSED_ARG(ssock);
  2770. + PJ_UNUSED_ARG(pool);
  2771. + PJ_UNUSED_ARG(buff_size);
  2772. + PJ_UNUSED_ARG(flags);
  2773. +
  2774. + return PJ_ENOTSUP;
  2775. +}
  2776. +
  2777. +
  2778. +/*
  2779. + * Same as #pj_ssl_sock_start_recvfrom() except that the recvfrom()
  2780. + * operation takes the buffer from the argument rather than creating
  2781. + * new ones.
  2782. + */
  2783. +PJ_DEF(pj_status_t) pj_ssl_sock_start_recvfrom2 (pj_ssl_sock_t *ssock,
  2784. + pj_pool_t *pool,
  2785. + unsigned buff_size,
  2786. + void *readbuf[],
  2787. + pj_uint32_t flags)
  2788. +{
  2789. + PJ_UNUSED_ARG(ssock);
  2790. + PJ_UNUSED_ARG(pool);
  2791. + PJ_UNUSED_ARG(buff_size);
  2792. + PJ_UNUSED_ARG(readbuf);
  2793. + PJ_UNUSED_ARG(flags);
  2794. +
  2795. + return PJ_ENOTSUP;
  2796. +}
  2797. +
  2798. +
  2799. +/*
  2800. + * Write the plain data to GnuTLS, it will be encrypted by gnutls_record_send()
  2801. + * and sent via tls_data_push. Note that re-negotitation may be on progress, so
  2802. + * sending data should be delayed until re-negotiation is completed.
  2803. + */
  2804. +static pj_status_t tls_write(pj_ssl_sock_t *ssock,
  2805. + pj_ioqueue_op_key_t *send_key,
  2806. + const void *data, pj_ssize_t size, unsigned flags)
  2807. +{
  2808. + pj_status_t status;
  2809. + int nwritten;
  2810. + pj_ssize_t total_written = 0;
  2811. +
  2812. + /* Ask GnuTLS to encrypt our plaintext now. GnuTLS will use the push
  2813. + * callback to actually write the encrypted bytes into our output circular
  2814. + * buffer. GnuTLS may refuse to "send" everything at once, but since we are
  2815. + * not really sending now, we will just call it again now until it succeeds
  2816. + * (or fails in a fatal way). */
  2817. + while (total_written < size) {
  2818. + /* Try encrypting using GnuTLS */
  2819. + nwritten = gnutls_record_send(ssock->session, ((read_data_t *)data) + total_written,
  2820. + size);
  2821. +
  2822. + if (nwritten > 0) {
  2823. + /* Good, some data was encrypted and written */
  2824. + total_written += nwritten;
  2825. + } else {
  2826. + /* Normally we would have to retry record_send but our internal
  2827. + * state has not changed, so we have to ask for more data first.
  2828. + * We will just try again later, although this should never happen.
  2829. + */
  2830. + return tls_status_from_err(ssock, nwritten);
  2831. + }
  2832. + }
  2833. +
  2834. + /* All encrypted data is written to the output circular buffer;
  2835. + * now send it on the socket (or notify problem). */
  2836. + if (total_written == size)
  2837. + status = flush_circ_buf_output(ssock, send_key, size, flags);
  2838. + else
  2839. + status = PJ_ENOMEM;
  2840. +
  2841. + return status;
  2842. +}
  2843. +
  2844. +
  2845. +/* Flush delayed data sending in the write pending list. */
  2846. +static pj_status_t flush_delayed_send(pj_ssl_sock_t *ssock)
  2847. +{
  2848. + /* Check for another ongoing flush */
  2849. + if (ssock->flushing_write_pend) {
  2850. + return PJ_EBUSY;
  2851. + }
  2852. +
  2853. + pj_lock_acquire(ssock->circ_buf_output_mutex);
  2854. +
  2855. + /* Again, check for another ongoing flush */
  2856. + if (ssock->flushing_write_pend) {
  2857. + pj_lock_release(ssock->circ_buf_output_mutex);
  2858. + return PJ_EBUSY;
  2859. + }
  2860. +
  2861. + /* Set ongoing flush flag */
  2862. + ssock->flushing_write_pend = PJ_TRUE;
  2863. +
  2864. + while (!pj_list_empty(&ssock->write_pending)) {
  2865. + write_data_t *wp;
  2866. + pj_status_t status;
  2867. +
  2868. + wp = ssock->write_pending.next;
  2869. +
  2870. + /* Ticket #1573: Don't hold mutex while calling socket send. */
  2871. + pj_lock_release(ssock->circ_buf_output_mutex);
  2872. +
  2873. + status = tls_write(ssock, &wp->key, wp->data.ptr,
  2874. + wp->plain_data_len, wp->flags);
  2875. + if (status != PJ_SUCCESS) {
  2876. + /* Reset ongoing flush flag first. */
  2877. + ssock->flushing_write_pend = PJ_FALSE;
  2878. + return status;
  2879. + }
  2880. +
  2881. + pj_lock_acquire(ssock->circ_buf_output_mutex);
  2882. + pj_list_erase(wp);
  2883. + pj_list_push_back(&ssock->write_pending_empty, wp);
  2884. + }
  2885. +
  2886. + /* Reset ongoing flush flag */
  2887. + ssock->flushing_write_pend = PJ_FALSE;
  2888. +
  2889. + pj_lock_release(ssock->circ_buf_output_mutex);
  2890. +
  2891. + return PJ_SUCCESS;
  2892. +}
  2893. +
  2894. +
  2895. +/* Sending is delayed, push back the sending data into pending list. */
  2896. +static pj_status_t delay_send(pj_ssl_sock_t *ssock,
  2897. + pj_ioqueue_op_key_t *send_key,
  2898. + const void *data, pj_ssize_t size,
  2899. + unsigned flags)
  2900. +{
  2901. + write_data_t *wp;
  2902. +
  2903. + pj_lock_acquire(ssock->circ_buf_output_mutex);
  2904. +
  2905. + /* Init write pending instance */
  2906. + if (!pj_list_empty(&ssock->write_pending_empty)) {
  2907. + wp = ssock->write_pending_empty.next;
  2908. + pj_list_erase(wp);
  2909. + } else {
  2910. + wp = PJ_POOL_ZALLOC_T(ssock->pool, write_data_t);
  2911. + }
  2912. +
  2913. + wp->app_key = send_key;
  2914. + wp->plain_data_len = size;
  2915. + wp->data.ptr = data;
  2916. + wp->flags = flags;
  2917. +
  2918. + pj_list_push_back(&ssock->write_pending, wp);
  2919. +
  2920. + pj_lock_release(ssock->circ_buf_output_mutex);
  2921. +
  2922. + /* Must return PJ_EPENDING */
  2923. + return PJ_EPENDING;
  2924. +}
  2925. +
  2926. +
  2927. +/**
  2928. + * Send data using the socket.
  2929. + */
  2930. +PJ_DEF(pj_status_t) pj_ssl_sock_send(pj_ssl_sock_t *ssock,
  2931. + pj_ioqueue_op_key_t *send_key,
  2932. + const void *data, pj_ssize_t *size,
  2933. + unsigned flags)
  2934. +{
  2935. + pj_status_t status;
  2936. +
  2937. + PJ_ASSERT_RETURN(ssock && data && size && (*size > 0), PJ_EINVAL);
  2938. + PJ_ASSERT_RETURN(ssock->connection_state==TLS_STATE_ESTABLISHED,
  2939. + PJ_EINVALIDOP);
  2940. +
  2941. + /* Flush delayed send first. Sending data might be delayed when
  2942. + * re-negotiation is on-progress. */
  2943. + status = flush_delayed_send(ssock);
  2944. + if (status == PJ_EBUSY) {
  2945. + /* Re-negotiation or flushing is on progress, delay sending */
  2946. + status = delay_send(ssock, send_key, data, *size, flags);
  2947. + goto on_return;
  2948. + } else if (status != PJ_SUCCESS) {
  2949. + goto on_return;
  2950. + }
  2951. +
  2952. + /* Write data to SSL */
  2953. + status = tls_write(ssock, send_key, data, *size, flags);
  2954. + if (status == PJ_EBUSY) {
  2955. + /* Re-negotiation is on progress, delay sending */
  2956. + status = delay_send(ssock, send_key, data, *size, flags);
  2957. + }
  2958. +
  2959. +on_return:
  2960. + return status;
  2961. +}
  2962. +
  2963. +
  2964. +/**
  2965. + * Send datagram using the socket.
  2966. + */
  2967. +PJ_DEF(pj_status_t) pj_ssl_sock_sendto (pj_ssl_sock_t *ssock,
  2968. + pj_ioqueue_op_key_t *send_key,
  2969. + const void *data, pj_ssize_t *size,
  2970. + unsigned flags,
  2971. + const pj_sockaddr_t *addr, int addr_len)
  2972. +{
  2973. + PJ_UNUSED_ARG(ssock);
  2974. + PJ_UNUSED_ARG(send_key);
  2975. + PJ_UNUSED_ARG(data);
  2976. + PJ_UNUSED_ARG(size);
  2977. + PJ_UNUSED_ARG(flags);
  2978. + PJ_UNUSED_ARG(addr);
  2979. + PJ_UNUSED_ARG(addr_len);
  2980. +
  2981. + return PJ_ENOTSUP;
  2982. +}
  2983. +
  2984. +/**
  2985. + * Starts asynchronous socket accept() operations on this secure socket.
  2986. + */
  2987. +PJ_DEF(pj_status_t) pj_ssl_sock_start_accept (pj_ssl_sock_t *ssock,
  2988. + pj_pool_t *pool,
  2989. + const pj_sockaddr_t *localaddr,
  2990. + int addr_len)
  2991. +{
  2992. + return pj_ssl_sock_start_accept2(ssock, pool, localaddr, addr_len,
  2993. + &ssock->param);
  2994. +}
  2995. +
  2996. +/**
  2997. + * Starts asynchronous socket accept() operations on this secure socket.
  2998. + */
  2999. +PJ_DEF(pj_status_t) pj_ssl_sock_start_accept2 (pj_ssl_sock_t *ssock,
  3000. + pj_pool_t *pool,
  3001. + const pj_sockaddr_t *localaddr,
  3002. + int addr_len,
  3003. + const pj_ssl_sock_param *newsock_param)
  3004. +{
  3005. + pj_activesock_cb asock_cb;
  3006. + pj_activesock_cfg asock_cfg;
  3007. + pj_status_t status;
  3008. +
  3009. + PJ_ASSERT_RETURN(ssock && pool && localaddr && addr_len, PJ_EINVAL);
  3010. +
  3011. + /* Verify new socket parameters */
  3012. + if (newsock_param->grp_lock != ssock->param.grp_lock ||
  3013. + newsock_param->sock_af != ssock->param.sock_af ||
  3014. + newsock_param->sock_type != ssock->param.sock_type)
  3015. + {
  3016. + return PJ_EINVAL;
  3017. + }
  3018. +
  3019. + /* Create socket */
  3020. + status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
  3021. + &ssock->sock);
  3022. + if (status != PJ_SUCCESS)
  3023. + goto on_error;
  3024. +
  3025. + /* Apply SO_REUSEADDR */
  3026. + if (ssock->param.reuse_addr) {
  3027. + int enabled = 1;
  3028. + status = pj_sock_setsockopt(ssock->sock, pj_SOL_SOCKET(),
  3029. + pj_SO_REUSEADDR(),
  3030. + &enabled, sizeof(enabled));
  3031. + if (status != PJ_SUCCESS) {
  3032. + PJ_PERROR(4,(ssock->pool->obj_name, status,
  3033. + "Warning: error applying SO_REUSEADDR"));
  3034. + }
  3035. + }
  3036. +
  3037. + /* Apply QoS, if specified */
  3038. + status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
  3039. + &ssock->param.qos_params, 2,
  3040. + ssock->pool->obj_name, NULL);
  3041. + if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
  3042. + goto on_error;
  3043. +
  3044. + /* Bind socket */
  3045. + status = pj_sock_bind(ssock->sock, localaddr, addr_len);
  3046. + if (status != PJ_SUCCESS)
  3047. + goto on_error;
  3048. +
  3049. + /* Start listening to the address */
  3050. + status = pj_sock_listen(ssock->sock, PJ_SOMAXCONN);
  3051. + if (status != PJ_SUCCESS)
  3052. + goto on_error;
  3053. +
  3054. + /* Create active socket */
  3055. + pj_activesock_cfg_default(&asock_cfg);
  3056. + asock_cfg.async_cnt = ssock->param.async_cnt;
  3057. + asock_cfg.concurrency = ssock->param.concurrency;
  3058. + asock_cfg.whole_data = PJ_TRUE;
  3059. +
  3060. + pj_bzero(&asock_cb, sizeof(asock_cb));
  3061. + asock_cb.on_accept_complete = asock_on_accept_complete;
  3062. +
  3063. + status = pj_activesock_create(pool,
  3064. + ssock->sock,
  3065. + ssock->param.sock_type,
  3066. + &asock_cfg,
  3067. + ssock->param.ioqueue,
  3068. + &asock_cb,
  3069. + ssock,
  3070. + &ssock->asock);
  3071. +
  3072. + if (status != PJ_SUCCESS)
  3073. + goto on_error;
  3074. +
  3075. + /* Start accepting */
  3076. + pj_ssl_sock_param_copy(pool, &ssock->newsock_param, newsock_param);
  3077. + status = pj_activesock_start_accept(ssock->asock, pool);
  3078. + if (status != PJ_SUCCESS)
  3079. + goto on_error;
  3080. +
  3081. + /* Update local address */
  3082. + ssock->addr_len = addr_len;
  3083. + status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
  3084. + &ssock->addr_len);
  3085. + if (status != PJ_SUCCESS)
  3086. + pj_sockaddr_cp(&ssock->local_addr, localaddr);
  3087. +
  3088. + ssock->is_server = PJ_TRUE;
  3089. +
  3090. + return PJ_SUCCESS;
  3091. +
  3092. +on_error:
  3093. + tls_sock_reset(ssock);
  3094. + return status;
  3095. +}
  3096. +
  3097. +
  3098. +/**
  3099. + * Starts asynchronous socket connect() operation.
  3100. + */
  3101. +PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
  3102. + pj_pool_t *pool,
  3103. + const pj_sockaddr_t *localaddr,
  3104. + const pj_sockaddr_t *remaddr,
  3105. + int addr_len)
  3106. +{
  3107. + pj_activesock_cb asock_cb;
  3108. + pj_activesock_cfg asock_cfg;
  3109. + pj_status_t status;
  3110. +
  3111. + PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
  3112. + PJ_EINVAL);
  3113. +
  3114. + /* Create socket */
  3115. + status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0,
  3116. + &ssock->sock);
  3117. + if (status != PJ_SUCCESS)
  3118. + goto on_error;
  3119. +
  3120. + /* Apply QoS, if specified */
  3121. + status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
  3122. + &ssock->param.qos_params, 2,
  3123. + ssock->pool->obj_name, NULL);
  3124. + if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
  3125. + goto on_error;
  3126. +
  3127. + /* Bind socket */
  3128. + status = pj_sock_bind(ssock->sock, localaddr, addr_len);
  3129. + if (status != PJ_SUCCESS)
  3130. + goto on_error;
  3131. +
  3132. + /* Create active socket */
  3133. + pj_activesock_cfg_default(&asock_cfg);
  3134. + asock_cfg.async_cnt = ssock->param.async_cnt;
  3135. + asock_cfg.concurrency = ssock->param.concurrency;
  3136. + asock_cfg.whole_data = PJ_TRUE;
  3137. +
  3138. + pj_bzero(&asock_cb, sizeof(asock_cb));
  3139. + asock_cb.on_connect_complete = asock_on_connect_complete;
  3140. + asock_cb.on_data_read = asock_on_data_read;
  3141. + asock_cb.on_data_sent = asock_on_data_sent;
  3142. +
  3143. + status = pj_activesock_create(pool,
  3144. + ssock->sock,
  3145. + ssock->param.sock_type,
  3146. + &asock_cfg,
  3147. + ssock->param.ioqueue,
  3148. + &asock_cb,
  3149. + ssock,
  3150. + &ssock->asock);
  3151. +
  3152. + if (status != PJ_SUCCESS)
  3153. + goto on_error;
  3154. +
  3155. + /* Save remote address */
  3156. + pj_sockaddr_cp(&ssock->rem_addr, remaddr);
  3157. +
  3158. + /* Start timer */
  3159. + if (ssock->param.timer_heap &&
  3160. + (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0))
  3161. + {
  3162. + pj_assert(ssock->timer.id == TIMER_NONE);
  3163. + ssock->timer.id = TIMER_HANDSHAKE_TIMEOUT;
  3164. + status = pj_timer_heap_schedule(ssock->param.timer_heap,
  3165. + &ssock->timer,
  3166. + &ssock->param.timeout);
  3167. + if (status != PJ_SUCCESS)
  3168. + ssock->timer.id = TIMER_NONE;
  3169. + }
  3170. +
  3171. + status = pj_activesock_start_connect(ssock->asock, pool, remaddr,
  3172. + addr_len);
  3173. +
  3174. + if (status == PJ_SUCCESS)
  3175. + asock_on_connect_complete(ssock->asock, PJ_SUCCESS);
  3176. + else if (status != PJ_EPENDING)
  3177. + goto on_error;
  3178. +
  3179. + /* Update local address */
  3180. + ssock->addr_len = addr_len;
  3181. + status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
  3182. + &ssock->addr_len);
  3183. + /* Note that we may not get an IP address here. This can
  3184. + * happen for example on Windows, where getsockname()
  3185. + * would return 0.0.0.0 if socket has just started the
  3186. + * async connect. In this case, just leave the local
  3187. + * address with 0.0.0.0 for now; it will be updated
  3188. + * once the socket is established.
  3189. + */
  3190. +
  3191. + /* Update socket state */
  3192. + ssock->is_server = PJ_FALSE;
  3193. +
  3194. + return PJ_EPENDING;
  3195. +
  3196. +on_error:
  3197. + tls_sock_reset(ssock);
  3198. + return status;
  3199. +}
  3200. +
  3201. +
  3202. +PJ_DEF(pj_status_t) pj_ssl_sock_renegotiate(pj_ssl_sock_t *ssock)
  3203. +{
  3204. + int status;
  3205. +
  3206. + /* Nothing established yet */
  3207. + PJ_ASSERT_RETURN(ssock->connection_state == TLS_STATE_ESTABLISHED,
  3208. + PJ_EINVALIDOP);
  3209. +
  3210. + /* Cannot renegotiate; we're a client */
  3211. + /* FIXME: in fact maybe that's not true */
  3212. + PJ_ASSERT_RETURN(!ssock->is_server, PJ_EINVALIDOP);
  3213. +
  3214. + /* First call gnutls_rehandshake() to see if this is even possible */
  3215. + status = gnutls_rehandshake(ssock->session);
  3216. +
  3217. + if (status == GNUTLS_E_SUCCESS) {
  3218. + /* Rehandshake is possible, so try a GnuTLS handshake now. The eventual
  3219. + * gnutls_record_recv() calls could return a few specific values during
  3220. + * this state:
  3221. + *
  3222. + * - GNUTLS_E_REHANDSHAKE: rehandshake message processing
  3223. + * - GNUTLS_E_WARNING_ALERT_RECEIVED: client does not wish to
  3224. + * renegotiate
  3225. + */
  3226. + ssock->connection_state = TLS_STATE_HANDSHAKING;
  3227. + status = tls_try_handshake(ssock);
  3228. +
  3229. + return status;
  3230. + } else {
  3231. + return tls_status_from_err(ssock, status);
  3232. + }
  3233. +}
  3234. +
  3235. +#endif /* PJ_HAS_SSL_SOCK */
  3236. diff -ru a/pjlib/src/pj/ssl_sock_ossl.c b/pjlib/src/pj/ssl_sock_ossl.c
  3237. --- a/pjlib/src/pj/ssl_sock_ossl.c 2017-01-24 00:41:05.000000000 -0500
  3238. +++ b/pjlib/src/pj/ssl_sock_ossl.c 2017-06-08 13:42:15.188809557 -0400
  3239. @@ -32,8 +32,10 @@
  3240. #include <pj/timer.h>
  3241. -/* Only build when PJ_HAS_SSL_SOCK is enabled */
  3242. -#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK!=0
  3243. +/* Only build when PJ_HAS_SSL_SOCK is enabled and when PJ_HAS_TLS_SOCK is
  3244. + * disabled (meaning GnuTLS is off) */
  3245. +#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
  3246. + defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
  3247. #define THIS_FILE "ssl_sock_ossl.c"
  3248. diff -ru a/pjmedia/src/pjmedia/transport_srtp.c b/pjmedia/src/pjmedia/transport_srtp.c
  3249. --- a/pjmedia/src/pjmedia/transport_srtp.c 2017-01-10 23:38:29.000000000 -0500
  3250. +++ b/pjmedia/src/pjmedia/transport_srtp.c 2017-06-08 13:43:29.727001721 -0400
  3251. @@ -30,7 +30,8 @@
  3252. #if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
  3253. -#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
  3254. +#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
  3255. + defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
  3256. # include <openssl/rand.h>
  3257. /* Suppress compile warning of OpenSSL deprecation (OpenSSL is deprecated
  3258. @@ -1147,7 +1148,8 @@
  3259. key_ok = PJ_TRUE;
  3260. -#if defined(PJ_HAS_SSL_SOCK) && (PJ_HAS_SSL_SOCK != 0)
  3261. +#if defined(PJ_HAS_SSL_SOCK) && PJ_HAS_SSL_SOCK != 0 && \
  3262. + defined(PJ_HAS_TLS_SOCK) && PJ_HAS_TLS_SOCK == 0
  3263. /* Include OpenSSL libraries for MSVC */
  3264. # ifdef _MSC_VER