diff --git a/control/controlclient/direct.go b/control/controlclient/direct.go index 36e9dd293..3eb2bca0c 100644 --- a/control/controlclient/direct.go +++ b/control/controlclient/direct.go @@ -16,6 +16,7 @@ import ( "io/ioutil" "log" "net/http" + "net/url" "os" "reflect" "strconv" @@ -114,6 +115,10 @@ func NewDirect(opts Options) (*Direct, error) { return nil, errors.New("controlclient.New: no server URL specified") } opts.ServerURL = strings.TrimRight(opts.ServerURL, "/") + serverURL, err := url.Parse(opts.ServerURL) + if err != nil { + return nil, err + } if opts.TimeNow == nil { opts.TimeNow = time.Now } @@ -125,7 +130,7 @@ func NewDirect(opts Options) (*Direct, error) { tr := http.DefaultTransport.(*http.Transport).Clone() tr.ForceAttemptHTTP2 = true - tr.TLSClientConfig = tlsdial.Config("", tr.TLSClientConfig) + tr.TLSClientConfig = tlsdial.Config(serverURL.Host, tr.TLSClientConfig) httpc := &http.Client{Transport: tr} c := &Direct{ diff --git a/net/tlsdial/tlsdial.go b/net/tlsdial/tlsdial.go index c7d6e26fb..b8012ad85 100644 --- a/net/tlsdial/tlsdial.go +++ b/net/tlsdial/tlsdial.go @@ -8,6 +8,8 @@ package tlsdial import "crypto/tls" +var platformModifyConf func(*tls.Config) + // Config returns a tls.Config for dialing the given host. // If base is non-nil, it's cloned as the base config before // being configured and returned. @@ -20,5 +22,9 @@ func Config(host string, base *tls.Config) *tls.Config { } conf.ServerName = host + if platformModifyConf != nil { + platformModifyConf(conf) + } + return conf } diff --git a/net/tlsdial/verify_darwin_arm64.go b/net/tlsdial/verify_darwin_arm64.go new file mode 100644 index 000000000..2c349c1fd --- /dev/null +++ b/net/tlsdial/verify_darwin_arm64.go @@ -0,0 +1,58 @@ +// Copyright (c) 2020 Tailscale Inc & AUTHORS All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin,arm64,usex509fork + +package tlsdial + +import ( + "crypto/tls" + "errors" + "time" + + "crypto/x509" + + x509fork "tailscale.com/tempfork/x509" +) + +func init() { + platformModifyConf = useX509Fork +} + +func useX509Fork(conf *tls.Config) { + // Modify conf to use our fork of crypto/x509 instead. + + // This prevents crypto/tls from using the standard library's + // x509. We will then be responsible for the rest. + conf.InsecureSkipVerify = true + + // Do what crypto/tls would've done for us: + conf.VerifyPeerCertificate = func(rawCerts [][]byte, _verifiedChains [][]*x509.Certificate) error { + if conf.ServerName == "" { + return errors.New("no tls.Config.ServerName set") + } + if len(rawCerts) == 0 { + // Shouldn't happen, but. + return errors.New("no rawCerts from server") + } + certs := make([]*x509fork.Certificate, len(rawCerts)) + for i, asn1Data := range rawCerts { + cert, err := x509fork.ParseCertificate(asn1Data) + if err != nil { + return err + } + certs[i] = cert + } + opts := x509fork.VerifyOptions{ + CurrentTime: time.Now(), + DNSName: conf.ServerName, + Intermediates: x509fork.NewCertPool(), + } + for _, cert := range certs[1:] { + opts.Intermediates.AddCert(cert) + } + _, err := certs[0].Verify(opts) + return err + } +}