Skip to content

Commit

Permalink
added client tls skip-verify and ca flags (closes jpillora#129 closes j…
Browse files Browse the repository at this point in the history
…pillora#116)

thanks to @mvladev and @alfonso-presa, I couldn't merge your PRs since I've done a massive refactor, though I borrowed snippets from them
  • Loading branch information
jpillora committed Jul 22, 2020
1 parent 878ab07 commit 7c997d2
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 11 deletions.
44 changes: 38 additions & 6 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package chclient

import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
Expand Down Expand Up @@ -38,15 +41,22 @@ type Config struct {
Proxy string
Remotes []string
Headers http.Header
TLS TLSConfig
DialContext func(ctx context.Context, network, addr string) (net.Conn, error)
}

type TLSConfig struct {
SkipVerify bool
CA string
}

//Client represents a client instance
type Client struct {
*cio.Logger
config *Config
computed settings.Config
sshConfig *ssh.ClientConfig
tlsConfig *tls.Config
proxyURL *url.URL
server string
connCount cnet.ConnCount
Expand All @@ -68,16 +78,16 @@ func NewClient(c *Config) (*Client, error) {
if err != nil {
return nil, err
}
//swap to websockets scheme
u.Scheme = strings.Replace(u.Scheme, "http", "ws", 1)
//apply default port
if !regexp.MustCompile(`:\d+$`).MatchString(u.Host) {
if u.Scheme == "https" || u.Scheme == "wss" {
if u.Scheme == "wss" {
u.Host = u.Host + ":443"
} else {
u.Host = u.Host + ":80"
}
}
//swap to websockets scheme
u.Scheme = strings.Replace(u.Scheme, "http", "ws", 1)
hasReverse := false
hasSocks := false
hasStdio := false
Expand All @@ -87,8 +97,31 @@ func NewClient(c *Config) (*Client, error) {
computed: settings.Config{
Version: chshare.BuildVersion,
},
server: u.String(),
server: u.String(),
tlsConfig: nil,
}
//set default log level
client.Logger.Info = true
//configure tls
if u.Scheme == "wss" {
tc := &tls.Config{}
if c.TLS.SkipVerify {
client.Infof("TLS verification disabled")
tc.InsecureSkipVerify = true
} else if c.TLS.CA != "" {
rootCAs := x509.NewCertPool()
if b, err := ioutil.ReadFile(c.TLS.CA); err != nil {
return nil, fmt.Errorf("Failed to load file: %s", c.TLS.CA)
} else if ok := rootCAs.AppendCertsFromPEM(b); !ok {
return nil, fmt.Errorf("Failed to decode PEM: %s", c.TLS.CA)
} else {
client.Infof("TLS verification using CA %s", c.TLS.CA)
tc.RootCAs = rootCAs
}
}
client.tlsConfig = tc
}
//validate remotes
for _, s := range c.Remotes {
r, err := settings.DecodeRemote(s)
if err != nil {
Expand All @@ -112,8 +145,6 @@ func NewClient(c *Config) (*Client, error) {
}
client.computed.Remotes = append(client.computed.Remotes, r)
}
//set default log level
client.Logger.Info = true
//outbound proxy
if p := c.Proxy; p != "" {
client.proxyURL, err = url.Parse(p)
Expand Down Expand Up @@ -241,6 +272,7 @@ func (c *Client) connectionOnce(ctx context.Context) (connected, retry bool, err
d := websocket.Dialer{
HandshakeTimeout: 45 * time.Second,
Subprotocols: []string{chshare.ProtocolVersion},
TLSClientConfig: c.tlsConfig,
}
//optional proxy
if p := c.proxyURL; p != nil {
Expand Down
14 changes: 14 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,18 @@ var clientHelp = `
--hostname, Optionally set the 'Host' header (defaults to the host
found in the server url).
--tls-ca, An optional root certificate bundle used to verify the
chisel server. Only valid when connecting to the server with
"https" or "wss". By default, the operating system CAs will be used.
--tls-skip-verify, Skip server TLS certificate verification of
chain and host name (if TLS is used for transport connections to
server). If set, client accepts any TLS certificate presented by
the server and any host name in that certificate. This only affects
transport https (wss) connection. Chisel server's public key
may be still verified (see --fingerprint) after inner connection
is established.
` + commonHelp

func client(args []string) {
Expand All @@ -365,6 +377,8 @@ func client(args []string) {
flags.IntVar(&config.MaxRetryCount, "max-retry-count", -1, "")
flags.DurationVar(&config.MaxRetryInterval, "max-retry-interval", 0, "")
flags.StringVar(&config.Proxy, "proxy", "", "")
flags.StringVar(&config.TLS.CA, "tls-ca", "", "")
flags.BoolVar(&config.TLS.SkipVerify, "tls-skip-verify", false, "")
flags.Var(&headerFlags{config.Headers}, "header", "")
hostname := flags.String("hostname", "", "")
pid := flags.Bool("pid", false, "")
Expand Down
2 changes: 1 addition & 1 deletion share/settings/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,9 +226,9 @@ func (r Remote) UserAddr() string {

//CanListen checks if the port can be listened on
func (r Remote) CanListen() bool {
//valid protocols
switch r.LocalProto {
case "tcp":
//valid
conn, err := net.Listen("tcp", r.Local())
if err == nil {
conn.Close()
Expand Down
2 changes: 1 addition & 1 deletion share/settings/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func NewUserIndex(logger *cio.Logger) *UserIndex {
// LoadUsers is responsible for loading users from a file
func (u *UserIndex) LoadUsers(configFile string) error {
u.configFile = configFile
u.Infof("Loading the configuraion from: %s", configFile)
u.Infof("Loading configuration file %s", configFile)
if err := u.loadUserIndex(); err != nil {
return err
}
Expand Down
4 changes: 1 addition & 3 deletions test/e2e/tls_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package e2e_test

//TODO tests for:
// PRE-REQ
// 1. add CA path to client config (update websocket.Dialer.TLSConfig)
// 2. generate local certs
// PRE-REQ generate local certs
// - client TLS (using local CA) -> server TLS (using local files)

0 comments on commit 7c997d2

Please sign in to comment.