github.com/psiphon-labs/psiphon-tunnel-core@v2.0.28+incompatible/psiphon/tlsDialer.go (about) 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 /* 21 Copyright (c) 2012 The Go Authors. All rights reserved. 22 23 Redistribution and use in source and binary forms, with or without 24 modification, are permitted provided that the following conditions are 25 met: 26 27 * Redistributions of source code must retain the above copyright 28 notice, this list of conditions and the following disclaimer. 29 * Redistributions in binary form must reproduce the above 30 copyright notice, this list of conditions and the following disclaimer 31 in the documentation and/or other materials provided with the 32 distribution. 33 * Neither the name of Google Inc. nor the names of its 34 contributors may be used to endorse or promote products derived from 35 this software without specific prior written permission. 36 37 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 38 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 39 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 40 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 41 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 44 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 45 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 46 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 47 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 48 */ 49 50 // Originally based on https://gopkg.in/getlantern/tlsdialer.v1. 51 52 package psiphon 53 54 import ( 55 "bytes" 56 "context" 57 "crypto/sha256" 58 "crypto/x509" 59 "encoding/base64" 60 "encoding/hex" 61 std_errors "errors" 62 "io/ioutil" 63 "net" 64 65 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common" 66 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors" 67 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters" 68 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng" 69 "github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol" 70 tris "github.com/Psiphon-Labs/tls-tris" 71 utls "github.com/Psiphon-Labs/utls" 72 ) 73 74 // CustomTLSConfig specifies the parameters for a CustomTLSDial, supporting 75 // many TLS-related network obfuscation mechanisms. 76 type CustomTLSConfig struct { 77 78 // Parameters is the active set of parameters.Parameters to use for the TLS 79 // dial. Must not be nil. 80 Parameters *parameters.Parameters 81 82 // Dial is the network connection dialer. TLS is layered on top of a new 83 // network connection created with dialer. Must not be nil. 84 Dial common.Dialer 85 86 // DialAddr overrides the "addr" input to Dial when specified 87 DialAddr string 88 89 // UseDialAddrSNI specifies whether to always use the dial "addr" 90 // host name in the SNI server_name field. When DialAddr is set, 91 // its host name is used. 92 UseDialAddrSNI bool 93 94 // SNIServerName specifies the value to set in the SNI 95 // server_name field. When blank, SNI is omitted. Note that 96 // underlying TLS code also automatically omits SNI when 97 // the server_name is an IP address. 98 // SNIServerName is ignored when UseDialAddrSNI is true. 99 SNIServerName string 100 101 // VerifyServerName specifies a domain name that must appear in the server 102 // certificate. When specified, certificate verification checks for 103 // VerifyServerName in the server certificate, in place of the dial or SNI 104 // hostname. 105 VerifyServerName string 106 107 // VerifyPins specifies one or more certificate pin values, one of which must 108 // appear in the verified server certificate chain. A pin value is the 109 // base64-encoded SHA2 digest of a certificate's public key. When specified, 110 // at least one pin must match at least one certificate in the chain, at any 111 // position; e.g., the root CA may be pinned, or the server certificate, 112 // etc. 113 VerifyPins []string 114 115 // VerifyLegacyCertificate is a special case self-signed server 116 // certificate case. Ignores IP SANs and basic constraints. No 117 // certificate chain. Just checks that the server presented the 118 // specified certificate. 119 // 120 // When VerifyLegacyCertificate is set, none of VerifyServerName, VerifyPins, 121 // SkipVerify may be set. 122 VerifyLegacyCertificate *x509.Certificate 123 124 // SkipVerify completely disables server certificate verification. 125 // 126 // When SkipVerify is set, none of VerifyServerName, VerifyPins, 127 // VerifyLegacyCertificate may be set. 128 SkipVerify bool 129 130 // TLSProfile specifies a particular indistinguishable TLS profile to use for 131 // the TLS dial. Setting TLSProfile allows the caller to pin the selection so 132 // all TLS connections in a certain context (e.g. a single meek connection) 133 // use a consistent value. The value should be selected by calling 134 // SelectTLSProfile, which will pick a value at random, subject to 135 // compatibility constraints. 136 // 137 // When TLSProfile is "", a profile is selected at random and 138 // DisableFrontingProviderTLSProfiles is ignored. 139 TLSProfile string 140 141 // NoDefaultTLSSessionID specifies whether to set a TLS session ID by 142 // default, for a new TLS connection that is not resuming a session. 143 // When nil, the parameter is set randomly. 144 NoDefaultTLSSessionID *bool 145 146 // RandomizedTLSProfileSeed specifies the PRNG seed to use when generating 147 // a randomized TLS ClientHello, which applies to TLS profiles where 148 // protocol.TLSProfileIsRandomized is true. The PRNG seed allows for 149 // optional replay of a particular randomized Client Hello. 150 RandomizedTLSProfileSeed *prng.Seed 151 152 // TLSPadding indicates whether to move or add a TLS padding extension to the 153 // front of the exension list and apply the specified padding length. Ignored 154 // when 0. 155 TLSPadding int 156 157 // TrustedCACertificatesFilename specifies a file containing trusted 158 // CA certs. See Config.TrustedCACertificatesFilename. 159 TrustedCACertificatesFilename string 160 161 // ObfuscatedSessionTicketKey enables obfuscated session tickets 162 // using the specified key. 163 ObfuscatedSessionTicketKey string 164 165 // PassthroughMessage, when specified, is a 32 byte value that is sent in the 166 // ClientHello random value field. The value should be generated using 167 // obfuscator.MakeTLSPassthroughMessage. 168 PassthroughMessage []byte 169 170 clientSessionCache utls.ClientSessionCache 171 } 172 173 // EnableClientSessionCache initializes a cache to use to persist session 174 // tickets, enabling TLS session resumability across multiple 175 // CustomTLSDial calls or dialers using the same CustomTLSConfig. 176 func (config *CustomTLSConfig) EnableClientSessionCache() { 177 if config.clientSessionCache == nil { 178 config.clientSessionCache = utls.NewLRUClientSessionCache(0) 179 } 180 } 181 182 // NewCustomTLSDialer creates a new dialer based on CustomTLSDial. 183 func NewCustomTLSDialer(config *CustomTLSConfig) common.Dialer { 184 return func(ctx context.Context, network, addr string) (net.Conn, error) { 185 return CustomTLSDial(ctx, network, addr, config) 186 } 187 } 188 189 // CustomTLSDial dials a new TLS connection using the parameters set in 190 // CustomTLSConfig. 191 // 192 // The dial aborts if ctx becomes Done before the dial completes. 193 func CustomTLSDial( 194 ctx context.Context, 195 network, addr string, 196 config *CustomTLSConfig) (net.Conn, error) { 197 198 if (config.SkipVerify && 199 (config.VerifyLegacyCertificate != nil || 200 len(config.VerifyServerName) > 0 || 201 len(config.VerifyPins) > 0)) || 202 203 (config.VerifyLegacyCertificate != nil && 204 (config.SkipVerify || 205 len(config.VerifyServerName) > 0 || 206 len(config.VerifyPins) > 0)) { 207 208 return nil, errors.TraceNew("incompatible certification verification parameters") 209 } 210 211 p := config.Parameters.Get() 212 213 dialAddr := addr 214 if config.DialAddr != "" { 215 dialAddr = config.DialAddr 216 } 217 218 rawConn, err := config.Dial(ctx, network, dialAddr) 219 if err != nil { 220 return nil, errors.Trace(err) 221 } 222 223 hostname, _, err := net.SplitHostPort(dialAddr) 224 if err != nil { 225 rawConn.Close() 226 return nil, errors.Trace(err) 227 } 228 229 var tlsConfigRootCAs *x509.CertPool 230 if !config.SkipVerify && 231 config.VerifyLegacyCertificate == nil && 232 config.TrustedCACertificatesFilename != "" { 233 234 tlsConfigRootCAs = x509.NewCertPool() 235 certData, err := ioutil.ReadFile(config.TrustedCACertificatesFilename) 236 if err != nil { 237 return nil, errors.Trace(err) 238 } 239 tlsConfigRootCAs.AppendCertsFromPEM(certData) 240 } 241 242 // In some cases, config.SkipVerify is false, but 243 // utls.Config.InsecureSkipVerify will be set to true to disable verification 244 // in utls that will otherwise fail: when SNI is omitted, and when 245 // VerifyServerName differs from SNI. In these cases, the certificate chain 246 // is verified in VerifyPeerCertificate. 247 248 tlsConfigInsecureSkipVerify := false 249 tlsConfigServerName := "" 250 verifyServerName := hostname 251 252 if config.SkipVerify { 253 tlsConfigInsecureSkipVerify = true 254 } 255 256 if config.UseDialAddrSNI { 257 258 // Set SNI to match the dial hostname. This is the standard case. 259 tlsConfigServerName = hostname 260 261 } else if config.SNIServerName != "" { 262 263 // Set a custom SNI value. If this value doesn't match the server 264 // certificate, SkipVerify and/or VerifyServerName may need to be 265 // configured; but by itself this case doesn't necessarily require 266 // custom certificate verification. 267 tlsConfigServerName = config.SNIServerName 268 269 } else { 270 271 // Omit SNI. If SkipVerify is not set, this case requires custom certificate 272 // verification, which will check that the server certificate matches either 273 // the dial hostname or VerifyServerName, as if the SNI were set to one of 274 // those values. 275 tlsConfigInsecureSkipVerify = true 276 } 277 278 // When VerifyServerName does not match the SNI, custom certificate 279 // verification is necessary. 280 if config.VerifyServerName != "" && config.VerifyServerName != tlsConfigServerName { 281 verifyServerName = config.VerifyServerName 282 tlsConfigInsecureSkipVerify = true 283 } 284 285 // With the VerifyPeerCertificate callback, we perform any custom certificate 286 // verification at the same point in the TLS handshake as standard utls 287 // verification; and abort the handshake at the same point, if custom 288 // verification fails. 289 var tlsConfigVerifyPeerCertificate func([][]byte, [][]*x509.Certificate) error 290 if !config.SkipVerify { 291 tlsConfigVerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { 292 293 if config.VerifyLegacyCertificate != nil { 294 return verifyLegacyCertificate( 295 rawCerts, config.VerifyLegacyCertificate) 296 } 297 298 if tlsConfigInsecureSkipVerify { 299 300 // Limitation: this verification path does not set the utls.Conn's 301 // ConnectionState certificate information. 302 303 if len(verifiedChains) > 0 { 304 return errors.TraceNew("unexpected verified chains") 305 } 306 var err error 307 verifiedChains, err = verifyServerCertificate( 308 tlsConfigRootCAs, rawCerts, verifyServerName) 309 if err != nil { 310 return errors.Trace(err) 311 } 312 } 313 314 if len(config.VerifyPins) > 0 { 315 err := verifyCertificatePins( 316 config.VerifyPins, verifiedChains) 317 if err != nil { 318 return errors.Trace(err) 319 } 320 } 321 322 return nil 323 } 324 } 325 326 tlsConfig := &utls.Config{ 327 RootCAs: tlsConfigRootCAs, 328 InsecureSkipVerify: tlsConfigInsecureSkipVerify, 329 ServerName: tlsConfigServerName, 330 VerifyPeerCertificate: tlsConfigVerifyPeerCertificate, 331 } 332 333 selectedTLSProfile := config.TLSProfile 334 335 if selectedTLSProfile == "" { 336 selectedTLSProfile = SelectTLSProfile(false, false, "", p) 337 } 338 339 utlsClientHelloID, utlsClientHelloSpec, err := getUTLSClientHelloID( 340 p, selectedTLSProfile) 341 if err != nil { 342 return nil, errors.Trace(err) 343 } 344 345 var randomizedTLSProfileSeed *prng.Seed 346 isRandomized := protocol.TLSProfileIsRandomized(selectedTLSProfile) 347 if isRandomized { 348 349 randomizedTLSProfileSeed = config.RandomizedTLSProfileSeed 350 351 if randomizedTLSProfileSeed == nil { 352 353 randomizedTLSProfileSeed, err = prng.NewSeed() 354 if err != nil { 355 return nil, errors.Trace(err) 356 } 357 } 358 359 utlsClientHelloID.Seed = new(utls.PRNGSeed) 360 *utlsClientHelloID.Seed = [32]byte(*randomizedTLSProfileSeed) 361 } 362 363 // As noted here, 364 // https://gitlab.com/yawning/obfs4/commit/ca6765e3e3995144df2b1ca9f0e9d823a7f8a47c, 365 // the dynamic record sizing optimization in crypto/tls is not commonly 366 // implemented in browsers. Disable it for all utls parrots and select it 367 // randomly when using the randomized client hello. 368 if isRandomized { 369 PRNG, err := prng.NewPRNGWithSaltedSeed(randomizedTLSProfileSeed, "tls-dynamic-record-sizing") 370 if err != nil { 371 return nil, errors.Trace(err) 372 } 373 tlsConfig.DynamicRecordSizingDisabled = PRNG.FlipCoin() 374 } else { 375 tlsConfig.DynamicRecordSizingDisabled = true 376 } 377 378 conn := utls.UClient(rawConn, tlsConfig, utlsClientHelloID) 379 380 if utlsClientHelloSpec != nil { 381 err := conn.ApplyPreset(utlsClientHelloSpec) 382 if err != nil { 383 return nil, errors.Trace(err) 384 } 385 } 386 387 clientSessionCache := config.clientSessionCache 388 if clientSessionCache == nil { 389 clientSessionCache = utls.NewLRUClientSessionCache(0) 390 } 391 392 conn.SetSessionCache(clientSessionCache) 393 394 // TODO: can conn.SetClientRandom be made to take effect if called here? In 395 // testing, the random value appears to be overwritten. As is, the overhead 396 // of needRemarshal is now always required to handle 397 // config.PassthroughMessage. 398 399 // Build handshake state in advance to obtain the TLS version, which is used 400 // to determine whether the following customizations may be applied. Don't use 401 // getClientHelloVersion, since that may incur additional overhead. 402 403 err = conn.BuildHandshakeState() 404 if err != nil { 405 return nil, errors.Trace(err) 406 } 407 408 isTLS13 := false 409 for _, vers := range conn.HandshakeState.Hello.SupportedVersions { 410 if vers == utls.VersionTLS13 { 411 isTLS13 = true 412 break 413 } 414 } 415 416 // Add the obfuscated session ticket only when using TLS 1.2. 417 // 418 // Obfuscated session tickets are not currently supported in TLS 1.3, but we 419 // allow UNFRONTED-MEEK-SESSION-TICKET-OSSH to use TLS 1.3 profiles for 420 // additional diversity/capacity; TLS 1.3 encrypts the server certificate, 421 // so the desired obfuscated session tickets property of obfuscating server 422 // certificates is satisfied. We know that when the ClientHello offers TLS 423 // 1.3, the Psiphon server, in these direct protocol cases, will negotiate 424 // it. 425 426 if config.ObfuscatedSessionTicketKey != "" && !isTLS13 { 427 428 var obfuscatedSessionTicketKey [32]byte 429 430 key, err := hex.DecodeString(config.ObfuscatedSessionTicketKey) 431 if err == nil && len(key) != 32 { 432 err = std_errors.New("invalid obfuscated session key length") 433 } 434 if err != nil { 435 return nil, errors.Trace(err) 436 } 437 copy(obfuscatedSessionTicketKey[:], key) 438 439 obfuscatedSessionState, err := tris.NewObfuscatedClientSessionState( 440 obfuscatedSessionTicketKey) 441 if err != nil { 442 return nil, errors.Trace(err) 443 } 444 445 conn.SetSessionState( 446 utls.MakeClientSessionState( 447 obfuscatedSessionState.SessionTicket, 448 obfuscatedSessionState.Vers, 449 obfuscatedSessionState.CipherSuite, 450 obfuscatedSessionState.MasterSecret, 451 nil, 452 nil)) 453 454 // Apply changes to utls 455 err = conn.BuildHandshakeState() 456 if err != nil { 457 return nil, errors.Trace(err) 458 } 459 460 // Ensure that TLS ClientHello has required session ticket extension and 461 // obfuscated session ticket cipher suite; the latter is required by 462 // utls/tls.Conn.loadSession. If these requirements are not met the 463 // obfuscation session ticket would be ignored, so fail. 464 465 if !tris.ContainsObfuscatedSessionTicketCipherSuite( 466 conn.HandshakeState.Hello.CipherSuites) { 467 return nil, errors.TraceNew( 468 "missing obfuscated session ticket cipher suite") 469 } 470 471 if len(conn.HandshakeState.Hello.SessionTicket) == 0 { 472 return nil, errors.TraceNew("missing session ticket extension") 473 } 474 } 475 476 // Perform at most one remarshal for the following ClientHello 477 // modifications. 478 needRemarshal := false 479 480 // Either pre-TLS 1.3 ClientHellos or any randomized ClientHello is a 481 // candidate for NoDefaultSessionID logic. 482 if len(conn.HandshakeState.Hello.SessionTicket) == 0 && 483 (!isTLS13 || utlsClientHelloID.Client == "Randomized") { 484 485 var noDefaultSessionID bool 486 if config.NoDefaultTLSSessionID != nil { 487 noDefaultSessionID = *config.NoDefaultTLSSessionID 488 } else { 489 noDefaultSessionID = config.Parameters.Get().WeightedCoinFlip( 490 parameters.NoDefaultTLSSessionIDProbability) 491 } 492 493 if noDefaultSessionID { 494 conn.HandshakeState.Hello.SessionId = nil 495 needRemarshal = true 496 } 497 } 498 499 // utls doesn't omit the server_name extension when the ServerName value is 500 // empty or an IP address. To avoid a fingerprintable invalid/unusual 501 // server_name extension, remove it in these cases. 502 if tlsConfigServerName == "" || net.ParseIP(tlsConfigServerName) != nil { 503 504 // Assumes only one SNIExtension. 505 // TODO: use new UConn.RemoveSNIExtension function? 506 deleteIndex := -1 507 for index, extension := range conn.Extensions { 508 if _, ok := extension.(*utls.SNIExtension); ok { 509 deleteIndex = index 510 break 511 } 512 } 513 if deleteIndex != -1 { 514 conn.Extensions = append( 515 conn.Extensions[:deleteIndex], conn.Extensions[deleteIndex+1:]...) 516 } 517 needRemarshal = true 518 } 519 520 if config.TLSPadding > 0 { 521 522 tlsPadding := config.TLSPadding 523 524 // Maximum padding size per RFC 7685 525 if tlsPadding > 65535 { 526 tlsPadding = 65535 527 } 528 529 // Assumes only one PaddingExtension. 530 deleteIndex := -1 531 for index, extension := range conn.Extensions { 532 if _, ok := extension.(*utls.UtlsPaddingExtension); ok { 533 deleteIndex = index 534 break 535 } 536 } 537 if deleteIndex != -1 { 538 conn.Extensions = append( 539 conn.Extensions[:deleteIndex], conn.Extensions[deleteIndex+1:]...) 540 } 541 542 paddingExtension := &utls.UtlsPaddingExtension{ 543 PaddingLen: tlsPadding, 544 WillPad: true, 545 } 546 conn.Extensions = append([]utls.TLSExtension{paddingExtension}, conn.Extensions...) 547 548 needRemarshal = true 549 550 } 551 552 if config.PassthroughMessage != nil { 553 err := conn.SetClientRandom(config.PassthroughMessage) 554 if err != nil { 555 return nil, errors.Trace(err) 556 } 557 558 needRemarshal = true 559 } 560 561 if needRemarshal { 562 // Apply changes to utls 563 err = conn.MarshalClientHello() 564 if err != nil { 565 return nil, errors.Trace(err) 566 } 567 } 568 569 // Perform the TLS Handshake. 570 571 resultChannel := make(chan error) 572 573 go func() { 574 resultChannel <- conn.Handshake() 575 }() 576 577 select { 578 case err = <-resultChannel: 579 case <-ctx.Done(): 580 err = ctx.Err() 581 // Interrupt the goroutine 582 rawConn.Close() 583 <-resultChannel 584 } 585 586 if err != nil { 587 rawConn.Close() 588 return nil, errors.Trace(err) 589 } 590 591 return conn, nil 592 } 593 594 func verifyLegacyCertificate(rawCerts [][]byte, expectedCertificate *x509.Certificate) error { 595 if len(rawCerts) < 1 { 596 return errors.TraceNew("missing certificate") 597 } 598 if !bytes.Equal(rawCerts[0], expectedCertificate.Raw) { 599 return errors.TraceNew("unexpected certificate") 600 } 601 return nil 602 } 603 604 func verifyServerCertificate( 605 rootCAs *x509.CertPool, rawCerts [][]byte, verifyServerName string) ([][]*x509.Certificate, error) { 606 607 // This duplicates the verification logic in utls (and standard crypto/tls). 608 609 certs := make([]*x509.Certificate, len(rawCerts)) 610 for i, rawCert := range rawCerts { 611 cert, err := x509.ParseCertificate(rawCert) 612 if err != nil { 613 return nil, errors.Trace(err) 614 } 615 certs[i] = cert 616 } 617 618 opts := x509.VerifyOptions{ 619 Roots: rootCAs, 620 DNSName: verifyServerName, 621 Intermediates: x509.NewCertPool(), 622 } 623 624 for i, cert := range certs { 625 if i == 0 { 626 continue 627 } 628 opts.Intermediates.AddCert(cert) 629 } 630 631 verifiedChains, err := certs[0].Verify(opts) 632 if err != nil { 633 return nil, errors.Trace(err) 634 } 635 636 return verifiedChains, nil 637 } 638 639 func verifyCertificatePins(pins []string, verifiedChains [][]*x509.Certificate) error { 640 for _, chain := range verifiedChains { 641 for _, cert := range chain { 642 publicKeyDigest := sha256.Sum256(cert.RawSubjectPublicKeyInfo) 643 expectedPin := base64.StdEncoding.EncodeToString(publicKeyDigest[:]) 644 if common.Contains(pins, expectedPin) { 645 // Return success on the first match of any certificate public key to any 646 // pin. 647 return nil 648 } 649 } 650 } 651 return errors.TraceNew("no pin found") 652 } 653 654 func IsTLSConnUsingHTTP2(conn net.Conn) bool { 655 if c, ok := conn.(*utls.UConn); ok { 656 state := c.ConnectionState() 657 return state.NegotiatedProtocolIsMutual && 658 state.NegotiatedProtocol == "h2" 659 } 660 return false 661 } 662 663 // SelectTLSProfile picks a TLS profile at random from the available candidates. 664 func SelectTLSProfile( 665 requireTLS12SessionTickets bool, 666 isFronted bool, 667 frontingProviderID string, 668 p parameters.ParametersAccessor) string { 669 670 // Two TLS profile lists are constructed, subject to limit constraints: 671 // stock, fixed parrots (non-randomized SupportedTLSProfiles) and custom 672 // parrots (CustomTLSProfileNames); and randomized. If one list is empty, the 673 // non-empty list is used. Otherwise SelectRandomizedTLSProfileProbability 674 // determines which list is used. 675 // 676 // Note that LimitTLSProfiles is not applied to CustomTLSProfiles; the 677 // presence of a candidate in CustomTLSProfiles is treated as explicit 678 // enabling. 679 // 680 // UseOnlyCustomTLSProfiles may be used to disable all stock TLS profiles and 681 // use only CustomTLSProfiles; UseOnlyCustomTLSProfiles is ignored if 682 // CustomTLSProfiles is empty. 683 // 684 // For fronted servers, DisableFrontingProviderTLSProfiles may be used 685 // to disable TLS profiles which are incompatible with the TLS stack used 686 // by the front. For example, if a utls parrot doesn't fully support all 687 // of the capabilities in the ClientHello. Unlike the LimitTLSProfiles case, 688 // DisableFrontingProviderTLSProfiles may disable CustomTLSProfiles. 689 690 limitTLSProfiles := p.TLSProfiles(parameters.LimitTLSProfiles) 691 var disableTLSProfiles protocol.TLSProfiles 692 693 if isFronted && frontingProviderID != "" { 694 disableTLSProfiles = p.LabeledTLSProfiles( 695 parameters.DisableFrontingProviderTLSProfiles, frontingProviderID) 696 } 697 698 randomizedTLSProfiles := make([]string, 0) 699 parrotTLSProfiles := make([]string, 0) 700 701 for _, tlsProfile := range p.CustomTLSProfileNames() { 702 if !common.Contains(disableTLSProfiles, tlsProfile) { 703 parrotTLSProfiles = append(parrotTLSProfiles, tlsProfile) 704 } 705 } 706 707 useOnlyCustomTLSProfiles := p.Bool(parameters.UseOnlyCustomTLSProfiles) 708 if useOnlyCustomTLSProfiles && len(parrotTLSProfiles) == 0 { 709 useOnlyCustomTLSProfiles = false 710 } 711 712 if !useOnlyCustomTLSProfiles { 713 for _, tlsProfile := range protocol.SupportedTLSProfiles { 714 715 if len(limitTLSProfiles) > 0 && 716 !common.Contains(limitTLSProfiles, tlsProfile) { 717 continue 718 } 719 720 if common.Contains(disableTLSProfiles, tlsProfile) { 721 continue 722 } 723 724 // requireTLS12SessionTickets is specified for 725 // UNFRONTED-MEEK-SESSION-TICKET-OSSH, a protocol which depends on using 726 // obfuscated session tickets to ensure that the server doesn't send its 727 // certificate in the TLS handshake. TLS 1.2 profiles which omit session 728 // tickets should not be selected. As TLS 1.3 encrypts the server 729 // certificate message, there's no exclusion for TLS 1.3. 730 731 if requireTLS12SessionTickets && 732 protocol.TLS12ProfileOmitsSessionTickets(tlsProfile) { 733 continue 734 } 735 736 if protocol.TLSProfileIsRandomized(tlsProfile) { 737 randomizedTLSProfiles = append(randomizedTLSProfiles, tlsProfile) 738 } else { 739 parrotTLSProfiles = append(parrotTLSProfiles, tlsProfile) 740 } 741 } 742 } 743 744 if len(randomizedTLSProfiles) > 0 && 745 (len(parrotTLSProfiles) == 0 || 746 p.WeightedCoinFlip(parameters.SelectRandomizedTLSProfileProbability)) { 747 748 return randomizedTLSProfiles[prng.Intn(len(randomizedTLSProfiles))] 749 } 750 751 if len(parrotTLSProfiles) == 0 { 752 return "" 753 } 754 755 return parrotTLSProfiles[prng.Intn(len(parrotTLSProfiles))] 756 } 757 758 func getUTLSClientHelloID( 759 p parameters.ParametersAccessor, 760 tlsProfile string) (utls.ClientHelloID, *utls.ClientHelloSpec, error) { 761 762 switch tlsProfile { 763 case protocol.TLS_PROFILE_IOS_111: 764 return utls.HelloIOS_11_1, nil, nil 765 case protocol.TLS_PROFILE_IOS_121: 766 return utls.HelloIOS_12_1, nil, nil 767 case protocol.TLS_PROFILE_IOS_13: 768 return utls.HelloIOS_13, nil, nil 769 case protocol.TLS_PROFILE_IOS_14: 770 return utls.HelloIOS_14, nil, nil 771 case protocol.TLS_PROFILE_CHROME_58: 772 return utls.HelloChrome_58, nil, nil 773 case protocol.TLS_PROFILE_CHROME_62: 774 return utls.HelloChrome_62, nil, nil 775 case protocol.TLS_PROFILE_CHROME_70: 776 return utls.HelloChrome_70, nil, nil 777 case protocol.TLS_PROFILE_CHROME_72: 778 return utls.HelloChrome_72, nil, nil 779 case protocol.TLS_PROFILE_CHROME_83: 780 return utls.HelloChrome_83, nil, nil 781 case protocol.TLS_PROFILE_CHROME_96: 782 return utls.HelloChrome_96, nil, nil 783 case protocol.TLS_PROFILE_CHROME_102: 784 return utls.HelloChrome_102, nil, nil 785 case protocol.TLS_PROFILE_FIREFOX_55: 786 return utls.HelloFirefox_55, nil, nil 787 case protocol.TLS_PROFILE_FIREFOX_56: 788 return utls.HelloFirefox_56, nil, nil 789 case protocol.TLS_PROFILE_FIREFOX_65: 790 return utls.HelloFirefox_65, nil, nil 791 case protocol.TLS_PROFILE_FIREFOX_99: 792 return utls.HelloFirefox_99, nil, nil 793 case protocol.TLS_PROFILE_FIREFOX_102: 794 return utls.HelloFirefox_102, nil, nil 795 case protocol.TLS_PROFILE_RANDOMIZED: 796 return utls.HelloRandomized, nil, nil 797 } 798 799 // utls.HelloCustom with a utls.ClientHelloSpec is used for 800 // CustomTLSProfiles. 801 802 customTLSProfile := p.CustomTLSProfile(tlsProfile) 803 if customTLSProfile == nil { 804 return utls.HelloCustom, 805 nil, 806 errors.Tracef("unknown TLS profile: %s", tlsProfile) 807 } 808 809 utlsClientHelloSpec, err := customTLSProfile.GetClientHelloSpec() 810 if err != nil { 811 return utls.ClientHelloID{}, nil, errors.Trace(err) 812 } 813 814 return utls.HelloCustom, utlsClientHelloSpec, nil 815 } 816 817 func getClientHelloVersion( 818 utlsClientHelloID utls.ClientHelloID, 819 utlsClientHelloSpec *utls.ClientHelloSpec) (string, error) { 820 821 switch utlsClientHelloID { 822 823 case utls.HelloIOS_11_1, utls.HelloIOS_12_1, utls.HelloChrome_58, 824 utls.HelloChrome_62, utls.HelloFirefox_55, utls.HelloFirefox_56: 825 return protocol.TLS_VERSION_12, nil 826 827 case utls.HelloChrome_70, utls.HelloChrome_72, utls.HelloChrome_83, 828 utls.HelloFirefox_65, utls.HelloGolang: 829 return protocol.TLS_VERSION_13, nil 830 } 831 832 // As utls.HelloRandomized/Custom may be either TLS 1.2 or TLS 1.3, we cannot 833 // perform a simple ClientHello ID check. BuildHandshakeState is run, which 834 // constructs the entire ClientHello. 835 // 836 // Assumes utlsClientHelloID.Seed has been set; otherwise the result is 837 // ephemeral. 838 // 839 // BenchmarkRandomizedGetClientHelloVersion indicates that this operation 840 // takes on the order of 0.05ms and allocates ~8KB for randomized client 841 // hellos. 842 843 conn := utls.UClient( 844 nil, 845 &utls.Config{InsecureSkipVerify: true}, 846 utlsClientHelloID) 847 848 if utlsClientHelloSpec != nil { 849 err := conn.ApplyPreset(utlsClientHelloSpec) 850 if err != nil { 851 return "", errors.Trace(err) 852 } 853 } 854 855 err := conn.BuildHandshakeState() 856 if err != nil { 857 return "", errors.Trace(err) 858 } 859 860 for _, v := range conn.HandshakeState.Hello.SupportedVersions { 861 if v == utls.VersionTLS13 { 862 return protocol.TLS_VERSION_13, nil 863 } 864 } 865 866 return protocol.TLS_VERSION_12, nil 867 } 868 869 func init() { 870 // Favor compatibility over security. CustomTLSDial is used as an obfuscation 871 // layer; users of CustomTLSDial, including meek and remote server list 872 // downloads, don't depend on this TLS for its security properties. 873 utls.EnableWeakCiphers() 874 }