tlsDialer.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. /*
  2. * Copyright (c) 2015, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. /*
  20. Copyright (c) 2012 The Go Authors. All rights reserved.
  21. Redistribution and use in source and binary forms, with or without
  22. modification, are permitted provided that the following conditions are
  23. met:
  24. * Redistributions of source code must retain the above copyright
  25. notice, this list of conditions and the following disclaimer.
  26. * Redistributions in binary form must reproduce the above
  27. copyright notice, this list of conditions and the following disclaimer
  28. in the documentation and/or other materials provided with the
  29. distribution.
  30. * Neither the name of Google Inc. nor the names of its
  31. contributors may be used to endorse or promote products derived from
  32. this software without specific prior written permission.
  33. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  34. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  35. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  36. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  37. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  38. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  39. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  40. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  41. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  43. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44. */
  45. // Based on https://github.com/getlantern/tlsdialer (http://gopkg.in/getlantern/tlsdialer.v1)
  46. // which itself is a "Fork of crypto/tls.Dial and DialWithDialer"
  47. package psiphon
  48. import (
  49. "bytes"
  50. "context"
  51. "crypto/x509"
  52. "encoding/hex"
  53. "errors"
  54. "fmt"
  55. "io/ioutil"
  56. "net"
  57. "time"
  58. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  59. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
  60. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
  61. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
  62. tris "github.com/Psiphon-Labs/tls-tris"
  63. utls "github.com/refraction-networking/utls"
  64. )
  65. // CustomTLSConfig contains parameters to determine the behavior
  66. // of CustomTLSDial.
  67. type CustomTLSConfig struct {
  68. // ClientParameters is the active set of client parameters to use
  69. // for the TLS dial.
  70. ClientParameters *parameters.ClientParameters
  71. // Dial is the network connection dialer. TLS is layered on
  72. // top of a new network connection created with dialer.
  73. Dial Dialer
  74. // DialAddr overrides the "addr" input to Dial when specified
  75. DialAddr string
  76. // UseDialAddrSNI specifies whether to always use the dial "addr"
  77. // host name in the SNI server_name field. When DialAddr is set,
  78. // its host name is used.
  79. UseDialAddrSNI bool
  80. // SNIServerName specifies the value to set in the SNI
  81. // server_name field. When blank, SNI is omitted. Note that
  82. // underlying TLS code also automatically omits SNI when
  83. // the server_name is an IP address.
  84. // SNIServerName is ignored when UseDialAddrSNI is true.
  85. SNIServerName string
  86. // SkipVerify completely disables server certificate verification.
  87. SkipVerify bool
  88. // VerifyLegacyCertificate is a special case self-signed server
  89. // certificate case. Ignores IP SANs and basic constraints. No
  90. // certificate chain. Just checks that the server presented the
  91. // specified certificate. SNI is disbled when this is set.
  92. VerifyLegacyCertificate *x509.Certificate
  93. // TLSProfile specifies a particular indistinguishable TLS profile to use
  94. // for the TLS dial. When TLSProfile is "", a profile is selected at
  95. // random. Setting TLSProfile allows the caller to pin the selection so
  96. // all TLS connections in a certain context (e.g. a single meek
  97. // connection) use a consistent value. The value should be selected by
  98. // calling SelectTLSProfile, which will pick a value at random, subject to
  99. // compatibility constraints.
  100. TLSProfile string
  101. // NoDefaultTLSSessionID specifies whether to set a TLS session ID by
  102. // default, for a new TLS connection that is not resuming a session.
  103. // When nil, the parameter is set randomly.
  104. NoDefaultTLSSessionID *bool
  105. // RandomizedTLSProfileSeed specifies the PRNG seed to use when generating
  106. // a randomized TLS ClientHello, which applies to TLS profiles where
  107. // protocol.TLSProfileIsRandomized is true. The PRNG seed allows for
  108. // optional replay of a particular randomized Client Hello.
  109. RandomizedTLSProfileSeed *prng.Seed
  110. // TrustedCACertificatesFilename specifies a file containing trusted
  111. // CA certs. See Config.TrustedCACertificatesFilename.
  112. TrustedCACertificatesFilename string
  113. // ObfuscatedSessionTicketKey enables obfuscated session tickets
  114. // using the specified key.
  115. ObfuscatedSessionTicketKey string
  116. clientSessionCache utls.ClientSessionCache
  117. }
  118. // EnableClientSessionCache initializes a cache to use to persist session
  119. // tickets, enabling TLS session resumability across multiple
  120. // CustomTLSDial calls or dialers using the same CustomTLSConfig.
  121. func (config *CustomTLSConfig) EnableClientSessionCache() {
  122. if config.clientSessionCache == nil {
  123. config.clientSessionCache = utls.NewLRUClientSessionCache(0)
  124. }
  125. }
  126. // SelectTLSProfile picks a TLS profile at random from the available candidates.
  127. func SelectTLSProfile(
  128. p parameters.ClientParametersAccessor) string {
  129. // Two TLS profile lists are constructed, subject to limit constraints:
  130. // stock, fixed parrots (non-randomized SupportedTLSProfiles) and custom
  131. // parrots (CustomTLSProfileNames); and randomized. If one list is empty, the
  132. // non-empty list is used. Otherwise SelectRandomizedTLSProfileProbability
  133. // determines which list is used.
  134. //
  135. // Note that LimitTLSProfiles is not applied to CustomTLSProfiles; the
  136. // presence of a candidate in CustomTLSProfiles is treated as explicit
  137. // enabling.
  138. //
  139. // UseOnlyCustomTLSProfiles may be used to disable all stock TLS profiles and
  140. // use only CustomTLSProfiles; UseOnlyCustomTLSProfiles is ignored if
  141. // CustomTLSProfiles is empty.
  142. limitTLSProfiles := p.TLSProfiles(parameters.LimitTLSProfiles)
  143. randomizedTLSProfiles := make([]string, 0)
  144. parrotTLSProfiles := p.CustomTLSProfileNames()
  145. useOnlyCustomTLSProfiles := p.Bool(parameters.UseOnlyCustomTLSProfiles)
  146. if useOnlyCustomTLSProfiles && len(parrotTLSProfiles) == 0 {
  147. useOnlyCustomTLSProfiles = false
  148. }
  149. if !useOnlyCustomTLSProfiles {
  150. for _, tlsProfile := range protocol.SupportedTLSProfiles {
  151. if len(limitTLSProfiles) > 0 &&
  152. !common.Contains(limitTLSProfiles, tlsProfile) {
  153. continue
  154. }
  155. if protocol.TLSProfileIsRandomized(tlsProfile) {
  156. randomizedTLSProfiles = append(randomizedTLSProfiles, tlsProfile)
  157. } else {
  158. parrotTLSProfiles = append(parrotTLSProfiles, tlsProfile)
  159. }
  160. }
  161. }
  162. if len(randomizedTLSProfiles) > 0 &&
  163. (len(parrotTLSProfiles) == 0 ||
  164. p.WeightedCoinFlip(parameters.SelectRandomizedTLSProfileProbability)) {
  165. return randomizedTLSProfiles[prng.Intn(len(randomizedTLSProfiles))]
  166. }
  167. if len(parrotTLSProfiles) == 0 {
  168. return ""
  169. }
  170. return parrotTLSProfiles[prng.Intn(len(parrotTLSProfiles))]
  171. }
  172. func getUTLSClientHelloID(
  173. p parameters.ClientParametersAccessor,
  174. tlsProfile string) (utls.ClientHelloID, *utls.ClientHelloSpec, error) {
  175. switch tlsProfile {
  176. case protocol.TLS_PROFILE_IOS_111:
  177. return utls.HelloIOS_11_1, nil, nil
  178. case protocol.TLS_PROFILE_IOS_121:
  179. return utls.HelloIOS_12_1, nil, nil
  180. case protocol.TLS_PROFILE_CHROME_58:
  181. return utls.HelloChrome_58, nil, nil
  182. case protocol.TLS_PROFILE_CHROME_62:
  183. return utls.HelloChrome_62, nil, nil
  184. case protocol.TLS_PROFILE_CHROME_70:
  185. return utls.HelloChrome_70, nil, nil
  186. case protocol.TLS_PROFILE_CHROME_72:
  187. return utls.HelloChrome_72, nil, nil
  188. case protocol.TLS_PROFILE_FIREFOX_55:
  189. return utls.HelloFirefox_55, nil, nil
  190. case protocol.TLS_PROFILE_FIREFOX_56:
  191. return utls.HelloFirefox_56, nil, nil
  192. case protocol.TLS_PROFILE_FIREFOX_65:
  193. return utls.HelloFirefox_65, nil, nil
  194. case protocol.TLS_PROFILE_RANDOMIZED:
  195. return utls.HelloRandomized, nil, nil
  196. }
  197. // utls.HelloCustom with a utls.ClientHelloSpec is used for
  198. // CustomTLSProfiles.
  199. customTLSProfile := p.CustomTLSProfile(tlsProfile)
  200. if customTLSProfile == nil {
  201. return utls.HelloCustom,
  202. nil,
  203. common.ContextError(fmt.Errorf("unknown TLS profile: %s", tlsProfile))
  204. }
  205. utlsClientHelloSpec, err := customTLSProfile.GetClientHelloSpec()
  206. if err != nil {
  207. return utls.ClientHelloID{}, nil, common.ContextError(err)
  208. }
  209. return utls.HelloCustom, utlsClientHelloSpec, nil
  210. }
  211. func getClientHelloVersion(
  212. utlsClientHelloID utls.ClientHelloID,
  213. utlsClientHelloSpec *utls.ClientHelloSpec) (string, error) {
  214. switch utlsClientHelloID {
  215. case utls.HelloIOS_11_1, utls.HelloIOS_12_1, utls.HelloChrome_58,
  216. utls.HelloChrome_62, utls.HelloFirefox_55, utls.HelloFirefox_56:
  217. return protocol.TLS_VERSION_12, nil
  218. case utls.HelloChrome_70, utls.HelloChrome_72, utls.HelloFirefox_65,
  219. utls.HelloGolang:
  220. return protocol.TLS_VERSION_13, nil
  221. }
  222. // As utls.HelloRandomized/Custom may be either TLS 1.2 or TLS 1.3, we cannot
  223. // perform a simple ClientHello ID check. BuildHandshakeState is run, which
  224. // constructs the entire ClientHello.
  225. //
  226. // Assumes utlsClientHelloID.Seed has been set; otherwise the result is
  227. // ephemeral.
  228. //
  229. // BenchmarkRandomizedGetClientHelloVersion indicates that this operation
  230. // takes on the order of 0.05ms and allocates ~8KB for randomized client
  231. // hellos.
  232. conn := utls.UClient(
  233. nil,
  234. &utls.Config{InsecureSkipVerify: true},
  235. utlsClientHelloID)
  236. if utlsClientHelloSpec != nil {
  237. err := conn.ApplyPreset(utlsClientHelloSpec)
  238. if err != nil {
  239. return "", common.ContextError(err)
  240. }
  241. }
  242. err := conn.BuildHandshakeState()
  243. if err != nil {
  244. return "", common.ContextError(err)
  245. }
  246. for _, v := range conn.HandshakeState.Hello.SupportedVersions {
  247. if v == utls.VersionTLS13 {
  248. return protocol.TLS_VERSION_13, nil
  249. }
  250. }
  251. return protocol.TLS_VERSION_12, nil
  252. }
  253. func IsTLSConnUsingHTTP2(conn net.Conn) bool {
  254. if c, ok := conn.(*utls.UConn); ok {
  255. state := c.ConnectionState()
  256. return state.NegotiatedProtocolIsMutual &&
  257. state.NegotiatedProtocol == "h2"
  258. }
  259. return false
  260. }
  261. // NewCustomTLSDialer creates a new dialer based on CustomTLSDial.
  262. func NewCustomTLSDialer(config *CustomTLSConfig) Dialer {
  263. return func(ctx context.Context, network, addr string) (net.Conn, error) {
  264. return CustomTLSDial(ctx, network, addr, config)
  265. }
  266. }
  267. // CustomTLSDial is a customized replacement for tls.Dial.
  268. // Based on tlsdialer.DialWithDialer which is based on crypto/tls.DialWithDialer.
  269. //
  270. // To ensure optimal TLS profile selection when using CustomTLSDial for tunnel
  271. // protocols, call SelectTLSProfile first and set its result into
  272. // config.TLSProfile.
  273. //
  274. // tlsdialer comment:
  275. // Note - if sendServerName is false, the VerifiedChains field on the
  276. // connection's ConnectionState will never get populated.
  277. func CustomTLSDial(
  278. ctx context.Context,
  279. network, addr string,
  280. config *CustomTLSConfig) (net.Conn, error) {
  281. p := config.ClientParameters.Get()
  282. dialAddr := addr
  283. if config.DialAddr != "" {
  284. dialAddr = config.DialAddr
  285. }
  286. rawConn, err := config.Dial(ctx, network, dialAddr)
  287. if err != nil {
  288. return nil, common.ContextError(err)
  289. }
  290. hostname, _, err := net.SplitHostPort(dialAddr)
  291. if err != nil {
  292. rawConn.Close()
  293. return nil, common.ContextError(err)
  294. }
  295. selectedTLSProfile := config.TLSProfile
  296. if selectedTLSProfile == "" {
  297. selectedTLSProfile = SelectTLSProfile(p)
  298. }
  299. tlsConfigInsecureSkipVerify := false
  300. tlsConfigServerName := ""
  301. if config.SkipVerify {
  302. tlsConfigInsecureSkipVerify = true
  303. }
  304. if config.UseDialAddrSNI {
  305. tlsConfigServerName = hostname
  306. } else if config.SNIServerName != "" && config.VerifyLegacyCertificate == nil {
  307. // Set the ServerName and rely on the usual logic in
  308. // tls.Conn.Handshake() to do its verification.
  309. // Note: Go TLS will automatically omit this ServerName when it's an IP address
  310. tlsConfigServerName = config.SNIServerName
  311. } else {
  312. // No SNI.
  313. // Disable verification in tls.Conn.Handshake(). We'll verify manually
  314. // after handshaking
  315. tlsConfigInsecureSkipVerify = true
  316. }
  317. var tlsRootCAs *x509.CertPool
  318. if !config.SkipVerify &&
  319. config.VerifyLegacyCertificate == nil &&
  320. config.TrustedCACertificatesFilename != "" {
  321. tlsRootCAs = x509.NewCertPool()
  322. certData, err := ioutil.ReadFile(config.TrustedCACertificatesFilename)
  323. if err != nil {
  324. return nil, common.ContextError(err)
  325. }
  326. tlsRootCAs.AppendCertsFromPEM(certData)
  327. }
  328. tlsConfig := &utls.Config{
  329. RootCAs: tlsRootCAs,
  330. InsecureSkipVerify: tlsConfigInsecureSkipVerify,
  331. ServerName: tlsConfigServerName,
  332. }
  333. utlsClientHelloID, utlsClientHelloSpec, err := getUTLSClientHelloID(
  334. p, selectedTLSProfile)
  335. if err != nil {
  336. return nil, common.ContextError(err)
  337. }
  338. var randomizedTLSProfileSeed *prng.Seed
  339. isRandomized := protocol.TLSProfileIsRandomized(selectedTLSProfile)
  340. if isRandomized {
  341. randomizedTLSProfileSeed = config.RandomizedTLSProfileSeed
  342. if randomizedTLSProfileSeed == nil {
  343. randomizedTLSProfileSeed, err = prng.NewSeed()
  344. if err != nil {
  345. return nil, common.ContextError(err)
  346. }
  347. }
  348. utlsClientHelloID.Seed = new(utls.PRNGSeed)
  349. *utlsClientHelloID.Seed = [32]byte(*randomizedTLSProfileSeed)
  350. }
  351. // As noted here,
  352. // https://gitlab.com/yawning/obfs4/commit/ca6765e3e3995144df2b1ca9f0e9d823a7f8a47c,
  353. // the dynamic record sizing optimization in crypto/tls is not commonly
  354. // implemented in browsers. Disable it for all utls parrots and select it
  355. // randomly when using the randomized client hello.
  356. if isRandomized {
  357. PRNG, err := prng.NewPRNGWithSaltedSeed(randomizedTLSProfileSeed, "tls-dynamic-record-sizing")
  358. if err != nil {
  359. return nil, common.ContextError(err)
  360. }
  361. tlsConfig.DynamicRecordSizingDisabled = PRNG.FlipCoin()
  362. } else {
  363. tlsConfig.DynamicRecordSizingDisabled = true
  364. }
  365. conn := utls.UClient(rawConn, tlsConfig, utlsClientHelloID)
  366. if utlsClientHelloSpec != nil {
  367. err := conn.ApplyPreset(utlsClientHelloSpec)
  368. if err != nil {
  369. return nil, common.ContextError(err)
  370. }
  371. }
  372. clientSessionCache := config.clientSessionCache
  373. if clientSessionCache == nil {
  374. clientSessionCache = utls.NewLRUClientSessionCache(0)
  375. }
  376. conn.SetSessionCache(clientSessionCache)
  377. // Build handshake state in advance to obtain the TLS version, which is used
  378. // to determine whether the following customizations may be applied. Don't use
  379. // getClientHelloVersion, since that may incur additional overhead.
  380. err = conn.BuildHandshakeState()
  381. if err != nil {
  382. return nil, common.ContextError(err)
  383. }
  384. isTLS13 := false
  385. for _, vers := range conn.HandshakeState.Hello.SupportedVersions {
  386. if vers == utls.VersionTLS13 {
  387. isTLS13 = true
  388. break
  389. }
  390. }
  391. // Add the obfuscated session ticket only when using TLS 1.2.
  392. //
  393. // Obfuscated session tickets are not currently supported in TLS 1.3, but we
  394. // allow UNFRONTED-MEEK-SESSION-TICKET-OSSH to use TLS 1.3 profiles for
  395. // additional diversity/capacity; TLS 1.3 encrypts the server certificate,
  396. // so the desired obfuscated session tickets property of obfuscating server
  397. // certificates is satisfied. We know that when the ClientHello offers TLS
  398. // 1.3, the Psiphon server, in these direct protocol cases, will negotiate
  399. // it.
  400. if config.ObfuscatedSessionTicketKey != "" && !isTLS13 {
  401. var obfuscatedSessionTicketKey [32]byte
  402. key, err := hex.DecodeString(config.ObfuscatedSessionTicketKey)
  403. if err == nil && len(key) != 32 {
  404. err = errors.New("invalid obfuscated session key length")
  405. }
  406. if err != nil {
  407. return nil, common.ContextError(err)
  408. }
  409. copy(obfuscatedSessionTicketKey[:], key)
  410. obfuscatedSessionState, err := tris.NewObfuscatedClientSessionState(
  411. obfuscatedSessionTicketKey)
  412. if err != nil {
  413. return nil, common.ContextError(err)
  414. }
  415. conn.SetSessionState(
  416. utls.MakeClientSessionState(
  417. obfuscatedSessionState.SessionTicket,
  418. obfuscatedSessionState.Vers,
  419. obfuscatedSessionState.CipherSuite,
  420. obfuscatedSessionState.MasterSecret,
  421. nil,
  422. nil))
  423. // Apply changes to utls
  424. err = conn.BuildHandshakeState()
  425. if err != nil {
  426. return nil, common.ContextError(err)
  427. }
  428. // Ensure that TLS ClientHello has required session ticket extension and
  429. // obfuscated session ticket cipher suite; the latter is required by
  430. // utls/tls.Conn.loadSession. If these requirements are not met the
  431. // obfuscation session ticket would be ignored, so fail.
  432. if !tris.ContainsObfuscatedSessionTicketCipherSuite(
  433. conn.HandshakeState.Hello.CipherSuites) {
  434. return nil, common.ContextError(
  435. errors.New("missing obfuscated session ticket cipher suite"))
  436. }
  437. if len(conn.HandshakeState.Hello.SessionTicket) == 0 {
  438. return nil, common.ContextError(
  439. errors.New("missing session ticket extension"))
  440. }
  441. }
  442. // Perform at most one remarshal for the following ClientHello
  443. // modifications.
  444. needRemarshal := false
  445. // Either pre-TLS 1.3 ClientHellos or any randomized ClientHello is a
  446. // candidate for NoDefaultSessionID logic.
  447. if len(conn.HandshakeState.Hello.SessionTicket) == 0 &&
  448. (!isTLS13 || utlsClientHelloID.Client == "Randomized") {
  449. var noDefaultSessionID bool
  450. if config.NoDefaultTLSSessionID != nil {
  451. noDefaultSessionID = *config.NoDefaultTLSSessionID
  452. } else {
  453. noDefaultSessionID = config.ClientParameters.Get().WeightedCoinFlip(
  454. parameters.NoDefaultTLSSessionIDProbability)
  455. }
  456. if noDefaultSessionID {
  457. conn.HandshakeState.Hello.SessionId = nil
  458. needRemarshal = true
  459. }
  460. }
  461. // utls doesn't omit the server_name extension when the SNI value is empty
  462. // (including both the case where we set the SNI value to "" and the case
  463. // where the SNI address is an IP address, which is internally changed to
  464. // ""). To avoid a fingerprintable invalid/unusual server_name extension,
  465. // remove it in these cases.
  466. if tlsConfigServerName == "" || net.ParseIP(tlsConfigServerName) != nil {
  467. // Assumes only one SNIExtension.
  468. deleteIndex := -1
  469. for index, extension := range conn.Extensions {
  470. if _, ok := extension.(*utls.SNIExtension); ok {
  471. deleteIndex = index
  472. break
  473. }
  474. }
  475. if deleteIndex != -1 {
  476. conn.Extensions = append(
  477. conn.Extensions[:deleteIndex], conn.Extensions[deleteIndex+1:]...)
  478. }
  479. needRemarshal = true
  480. }
  481. if needRemarshal {
  482. // Apply changes to utls
  483. err = conn.MarshalClientHello()
  484. if err != nil {
  485. return nil, common.ContextError(err)
  486. }
  487. }
  488. // Perform the TLS Handshake.
  489. resultChannel := make(chan error)
  490. go func() {
  491. resultChannel <- conn.Handshake()
  492. }()
  493. select {
  494. case err = <-resultChannel:
  495. case <-ctx.Done():
  496. err = ctx.Err()
  497. // Interrupt the goroutine
  498. rawConn.Close()
  499. <-resultChannel
  500. }
  501. if err == nil && !config.SkipVerify && tlsConfigInsecureSkipVerify {
  502. if config.VerifyLegacyCertificate != nil {
  503. err = verifyLegacyCertificate(conn, config.VerifyLegacyCertificate)
  504. } else {
  505. // Manually verify certificates
  506. err = verifyServerCerts(conn, hostname)
  507. }
  508. }
  509. if err != nil {
  510. rawConn.Close()
  511. return nil, common.ContextError(err)
  512. }
  513. return conn, nil
  514. }
  515. func verifyLegacyCertificate(conn *utls.UConn, expectedCertificate *x509.Certificate) error {
  516. certs := conn.ConnectionState().PeerCertificates
  517. if len(certs) < 1 {
  518. return common.ContextError(errors.New("no certificate to verify"))
  519. }
  520. if !bytes.Equal(certs[0].Raw, expectedCertificate.Raw) {
  521. return common.ContextError(errors.New("unexpected certificate"))
  522. }
  523. return nil
  524. }
  525. func verifyServerCerts(conn *utls.UConn, hostname string) error {
  526. certs := conn.ConnectionState().PeerCertificates
  527. opts := x509.VerifyOptions{
  528. Roots: nil, // Use host's root CAs
  529. CurrentTime: time.Now(),
  530. DNSName: hostname,
  531. Intermediates: x509.NewCertPool(),
  532. }
  533. for i, cert := range certs {
  534. if i == 0 {
  535. continue
  536. }
  537. opts.Intermediates.AddCert(cert)
  538. }
  539. _, err := certs[0].Verify(opts)
  540. if err != nil {
  541. return common.ContextError(err)
  542. }
  543. return nil
  544. }
  545. func init() {
  546. // Favor compatibility over security. CustomTLSDial is used as an obfuscation
  547. // layer; users of CustomTLSDial, including meek and remote server list
  548. // downloads, don't depend on this TLS for its security properties.
  549. utls.EnableWeakCiphers()
  550. }