customTLSProfiles.go 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Copyright (c) 2019, 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 protocol
  20. import (
  21. "crypto/sha256"
  22. "encoding/json"
  23. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
  24. "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
  25. utls "github.com/refraction-networking/utls"
  26. )
  27. // CustomTLSProfile specifies custom TLS profile. This is used to deploy
  28. // custom ClientHellos as tactics data.
  29. type CustomTLSProfile struct {
  30. Name string
  31. UTLSSpec *UTLSSpec
  32. }
  33. type CustomTLSProfiles []*CustomTLSProfile
  34. // Validate checks that the profiles in CustomTLSProfiles are initialized and
  35. // have no name conflicts.
  36. func (profiles CustomTLSProfiles) Validate() error {
  37. names := make(map[string]bool)
  38. for _, p := range profiles {
  39. if p.Name == "" {
  40. return errors.Tracef("custom TLS profile missing name: %s", p.Name)
  41. }
  42. if p.UTLSSpec == nil {
  43. return errors.Tracef("custom TLS profile missing utls spec: %s", p.Name)
  44. }
  45. if common.Contains(SupportedTLSProfiles, p.Name) ||
  46. common.Contains(legacyTLSProfiles, p.Name) {
  47. return errors.Tracef("invalid custom TLS profile name: %s", p.Name)
  48. }
  49. if _, ok := names[p.Name]; ok {
  50. return errors.Tracef("duplicate custom TLS profile name: %s", p.Name)
  51. }
  52. names[p.Name] = true
  53. }
  54. return nil
  55. }
  56. // GetClientHelloSpec creates a new utls.ClientHelloSpec from the ClientHello
  57. // definition in UTLSpec.
  58. //
  59. // A new utls.ClientHelloSpec, with no shared data, is created for each call,
  60. // as per:
  61. // https://github.com/refraction-networking/utls/blob/4da67951864128358459681399dd208c49d5d001/u_parrots.go#L483
  62. func (profile *CustomTLSProfile) GetClientHelloSpec() (*utls.ClientHelloSpec, error) {
  63. spec := &utls.ClientHelloSpec{}
  64. spec.TLSVersMin = profile.UTLSSpec.TLSVersMin
  65. spec.TLSVersMax = profile.UTLSSpec.TLSVersMax
  66. spec.CipherSuites = append([]uint16(nil), profile.UTLSSpec.CipherSuites...)
  67. spec.CompressionMethods = append([]uint8(nil), profile.UTLSSpec.CompressionMethods...)
  68. spec.Extensions = make([]utls.TLSExtension, len(profile.UTLSSpec.Extensions))
  69. for i, extension := range profile.UTLSSpec.Extensions {
  70. var err error
  71. spec.Extensions[i], err = extension.GetUTLSExtension()
  72. if err != nil {
  73. return nil, errors.Trace(err)
  74. }
  75. }
  76. if profile.UTLSSpec.GetSessionID == "SHA-256" {
  77. spec.GetSessionID = sha256.Sum256
  78. }
  79. return spec, nil
  80. }
  81. // UTLSSpec is a parallel data structure mirroring utls.ClientHelloSpec. Note
  82. // that utls.ClientHelloSpec cannot be directly marshaled with encoding/json
  83. // nor encoding/gob due to various type restrictions which
  84. // utls.ClientHelloSpec does not meet. Nor can we simply transmit a static,
  85. // raw ClientHello since concrete utls extension types must be instantiated in
  86. // order for related functionality to be enabled.
  87. // UTLSSpec specifies a utls.ClientHelloSpec.
  88. type UTLSSpec struct {
  89. TLSVersMin uint16
  90. TLSVersMax uint16
  91. CipherSuites []uint16
  92. CompressionMethods []uint8
  93. Extensions []*UTLSExtension
  94. GetSessionID string
  95. }
  96. // UTLSExtension specifies one of the several utls.TLSExtension concrete
  97. // implementations.
  98. type UTLSExtension struct {
  99. Name string
  100. Data json.RawMessage
  101. }
  102. // GetUTLSExtension instantiates the specified utls.TLSExtension concrete
  103. // implementation.
  104. func (e *UTLSExtension) GetUTLSExtension() (utls.TLSExtension, error) {
  105. switch e.Name {
  106. case "NPN":
  107. var extension *utls.NPNExtension
  108. err := json.Unmarshal(e.Data, &extension)
  109. if err != nil {
  110. return nil, errors.Trace(err)
  111. }
  112. return extension, nil
  113. case "SNI":
  114. return &utls.SNIExtension{}, nil
  115. case "StatusRequest":
  116. return &utls.StatusRequestExtension{}, nil
  117. case "SupportedCurves":
  118. var extension *utls.SupportedCurvesExtension
  119. err := json.Unmarshal(e.Data, &extension)
  120. if err != nil {
  121. return nil, errors.Trace(err)
  122. }
  123. return extension, nil
  124. case "SupportedPoints":
  125. var extension *utls.SupportedPointsExtension
  126. err := json.Unmarshal(e.Data, &extension)
  127. if err != nil {
  128. return nil, errors.Trace(err)
  129. }
  130. return extension, nil
  131. case "SignatureAlgorithms":
  132. var extension *utls.SignatureAlgorithmsExtension
  133. err := json.Unmarshal(e.Data, &extension)
  134. if err != nil {
  135. return nil, errors.Trace(err)
  136. }
  137. return extension, nil
  138. case "RenegotiationInfo":
  139. var extension *utls.RenegotiationInfoExtension
  140. err := json.Unmarshal(e.Data, &extension)
  141. if err != nil {
  142. return nil, errors.Trace(err)
  143. }
  144. return extension, nil
  145. case "ALPN":
  146. var extension *utls.ALPNExtension
  147. err := json.Unmarshal(e.Data, &extension)
  148. if err != nil {
  149. return nil, errors.Trace(err)
  150. }
  151. return extension, nil
  152. case "SCT":
  153. return &utls.SCTExtension{}, nil
  154. case "SessionTicket":
  155. return &utls.SessionTicketExtension{}, nil
  156. case "Generic":
  157. var extension *utls.GenericExtension
  158. err := json.Unmarshal(e.Data, &extension)
  159. if err != nil {
  160. return nil, errors.Trace(err)
  161. }
  162. return extension, nil
  163. case "ExtendedMasterSecret":
  164. return &utls.UtlsExtendedMasterSecretExtension{}, nil
  165. case "GREASE":
  166. return &utls.UtlsGREASEExtension{}, nil
  167. case "BoringPadding":
  168. return &utls.UtlsPaddingExtension{GetPaddingLen: utls.BoringPaddingStyle}, nil
  169. case "KeyShare":
  170. var extension *utls.KeyShareExtension
  171. err := json.Unmarshal(e.Data, &extension)
  172. if err != nil {
  173. return nil, errors.Trace(err)
  174. }
  175. return extension, nil
  176. case "PSKKeyExchangeModes":
  177. var extension *utls.PSKKeyExchangeModesExtension
  178. err := json.Unmarshal(e.Data, &extension)
  179. if err != nil {
  180. return nil, errors.Trace(err)
  181. }
  182. return extension, nil
  183. case "SupportedVersions":
  184. var extension *utls.SupportedVersionsExtension
  185. err := json.Unmarshal(e.Data, &extension)
  186. if err != nil {
  187. return nil, errors.Trace(err)
  188. }
  189. return extension, nil
  190. case "ChannelID":
  191. return &utls.FakeChannelIDExtension{}, nil
  192. case "CertCompressionAlgs":
  193. var extension *utls.UtlsCompressCertExtension
  194. err := json.Unmarshal(e.Data, &extension)
  195. if err != nil {
  196. return nil, errors.Trace(err)
  197. }
  198. return extension, nil
  199. case "RecordSizeLimit":
  200. var extension *utls.FakeRecordSizeLimitExtension
  201. err := json.Unmarshal(e.Data, &extension)
  202. if err != nil {
  203. return nil, errors.Trace(err)
  204. }
  205. return extension, nil
  206. case "ALPS":
  207. var extension *utls.ApplicationSettingsExtension
  208. err := json.Unmarshal(e.Data, &extension)
  209. if err != nil {
  210. return nil, errors.Trace(err)
  211. }
  212. return extension, nil
  213. case "DelegatedCredentials":
  214. var extension *utls.DelegatedCredentialsExtension
  215. err := json.Unmarshal(e.Data, &extension)
  216. if err != nil {
  217. return nil, errors.Trace(err)
  218. }
  219. return extension, nil
  220. }
  221. return nil, errors.Tracef("unknown utls extension: %s", e.Name)
  222. }