tlsTunnelConn.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * Copyright (c) 2023, 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. package psiphon
  20. import (
  21. "context"
  22. "net"
  23. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  24. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  25. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/obfuscator"
  26. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
  27. )
  28. // TLSTunnelConfig specifies the behavior of a TLSTunnelConn.
  29. type TLSTunnelConfig struct {
  30. // CustomTLSConfig is the parameters that will be used to esablish a new
  31. // TLS connection with CustomTLSDial.
  32. CustomTLSConfig *CustomTLSConfig
  33. // UseObfuscatedSessionTickets indicates whether to use obfuscated session
  34. // tickets.
  35. UseObfuscatedSessionTickets bool
  36. // The following values are used to create the TLS passthrough message.
  37. ObfuscatedKey string
  38. ObfuscatorPaddingSeed *prng.Seed
  39. }
  40. // TLSTunnelConn is a network connection that tunnels net.Conn flows over TLS.
  41. type TLSTunnelConn struct {
  42. net.Conn
  43. tlsPadding int
  44. }
  45. // DialTLSTunnel returns an initialized tls-tunnel connection.
  46. func DialTLSTunnel(
  47. ctx context.Context,
  48. tlsTunnelConfig *TLSTunnelConfig,
  49. dialConfig *DialConfig,
  50. tlsOSSHApplyTrafficShaping bool,
  51. tlsOSSHMinTLSPadding,
  52. tlsOSSHMaxTLSPadding int,
  53. ) (*TLSTunnelConn, error) {
  54. tlsPadding,
  55. err :=
  56. tlsTunnelTLSPadding(
  57. tlsOSSHApplyTrafficShaping,
  58. tlsOSSHMinTLSPadding,
  59. tlsOSSHMaxTLSPadding,
  60. tlsTunnelConfig.ObfuscatorPaddingSeed)
  61. if err != nil {
  62. return nil, errors.Trace(err)
  63. }
  64. tlsConfig := &CustomTLSConfig{
  65. Parameters: tlsTunnelConfig.CustomTLSConfig.Parameters,
  66. Dial: NewTCPDialer(dialConfig),
  67. DialAddr: tlsTunnelConfig.CustomTLSConfig.DialAddr,
  68. SNIServerName: tlsTunnelConfig.CustomTLSConfig.SNIServerName,
  69. VerifyServerName: tlsTunnelConfig.CustomTLSConfig.VerifyServerName,
  70. VerifyPins: tlsTunnelConfig.CustomTLSConfig.VerifyPins,
  71. SkipVerify: tlsTunnelConfig.CustomTLSConfig.SkipVerify,
  72. TLSProfile: tlsTunnelConfig.CustomTLSConfig.TLSProfile,
  73. NoDefaultTLSSessionID: tlsTunnelConfig.CustomTLSConfig.NoDefaultTLSSessionID,
  74. RandomizedTLSProfileSeed: tlsTunnelConfig.CustomTLSConfig.RandomizedTLSProfileSeed,
  75. TLSPadding: tlsPadding,
  76. TrustedCACertificatesFilename: dialConfig.TrustedCACertificatesFilename,
  77. FragmentClientHello: tlsTunnelConfig.CustomTLSConfig.FragmentClientHello,
  78. }
  79. tlsConfig.EnableClientSessionCache()
  80. if tlsTunnelConfig.UseObfuscatedSessionTickets {
  81. tlsConfig.ObfuscatedSessionTicketKey = tlsTunnelConfig.ObfuscatedKey
  82. }
  83. // As the passthrough message is unique and indistinguishable from a normal
  84. // TLS client random value, we set it unconditionally and not just for
  85. // protocols which may support passthrough (even for those protocols,
  86. // clients don't know which servers are configured to use it).
  87. passthroughMessage, err := obfuscator.MakeTLSPassthroughMessage(
  88. true,
  89. tlsTunnelConfig.ObfuscatedKey)
  90. if err != nil {
  91. return nil, errors.Trace(err)
  92. }
  93. tlsConfig.PassthroughMessage = passthroughMessage
  94. tlsDialer := NewCustomTLSDialer(tlsConfig)
  95. // As DialAddr is set in the CustomTLSConfig, no address is required here.
  96. conn, err := tlsDialer(ctx, "tcp", "")
  97. if err != nil {
  98. return nil, errors.Trace(err)
  99. }
  100. return &TLSTunnelConn{
  101. Conn: conn,
  102. tlsPadding: tlsPadding,
  103. }, nil
  104. }
  105. // tlsTunnelTLSPadding returns the padding length to apply with the TLS padding
  106. // extension to the TLS conn established with NewCustomTLSDialer. See
  107. // CustomTLSConfig.TLSPadding for details.
  108. func tlsTunnelTLSPadding(
  109. tlsOSSHApplyTrafficShaping bool,
  110. tlsOSSHMinTLSPadding int,
  111. tlsOSSHMaxTLSPadding int,
  112. obfuscatorPaddingPRNGSeed *prng.Seed,
  113. ) (tlsPadding int,
  114. err error) {
  115. tlsPadding = 0
  116. if tlsOSSHApplyTrafficShaping {
  117. minPadding := tlsOSSHMinTLSPadding
  118. maxPadding := tlsOSSHMaxTLSPadding
  119. // Maximum padding size per RFC 7685
  120. if maxPadding > 65535 {
  121. maxPadding = 65535
  122. }
  123. if maxPadding > 0 {
  124. tlsPaddingPRNG, err := prng.NewPRNGWithSaltedSeed(obfuscatorPaddingPRNGSeed, "tls-padding")
  125. if err != nil {
  126. return 0, errors.Trace(err)
  127. }
  128. tlsPadding = tlsPaddingPRNG.Range(minPadding, maxPadding)
  129. }
  130. }
  131. return tlsPadding, nil
  132. }
  133. func (conn *TLSTunnelConn) GetMetrics() common.LogFields {
  134. logFields := make(common.LogFields)
  135. logFields["tls_padding"] = conn.tlsPadding
  136. // Include metrics, such as fragmentor metrics, from the underlying dial
  137. // conn. Properties of subsequent underlying dial conns are not reflected
  138. // in these metrics; we assume that the first dial conn, which most likely
  139. // transits the various protocol handshakes, is most significant.
  140. underlyingMetrics, ok := conn.Conn.(common.MetricsSource)
  141. if ok {
  142. logFields.Add(underlyingMetrics.GetMetrics())
  143. }
  144. return logFields
  145. }
  146. func (conn *TLSTunnelConn) IsClosed() bool {
  147. closer, ok := conn.Conn.(common.Closer)
  148. if !ok {
  149. return false
  150. }
  151. return closer.IsClosed()
  152. }