From edaddb0d95d9313f21d9a4bb40bc6232b87c0361 Mon Sep 17 00:00:00 2001 From: Javed Khan Date: Fri, 9 Jan 2015 14:50:59 +0530 Subject: [PATCH] Allow disabling RPC client TLS for localhost only. This commit introduces a new flag, --noclienttls, which can be used to disable TLS for the RPC client. However, the flag can only be used when the RPC client is connecting to localhost interfaces. This is intended to prevent accidentally leaking sensitive data when switching between local and remote servers. --- btcwallet.go | 17 ++++++++++------- chain/chain.go | 3 ++- config.go | 46 ++++++++++++++++++++++++++-------------------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/btcwallet.go b/btcwallet.go index 6ea6e32..eca5d43 100644 --- a/btcwallet.go +++ b/btcwallet.go @@ -90,15 +90,18 @@ func walletMain() error { go func() { // Read CA certs and create the RPC client. - certs, err := ioutil.ReadFile(cfg.CAFile) - if err != nil { - log.Warnf("Cannot open CA file: %v", err) - // If there's an error reading the CA file, continue - // with nil certs and without the client connection - certs = nil + var certs []byte + if !cfg.DisableClientTLS { + certs, err = ioutil.ReadFile(cfg.CAFile) + if err != nil { + log.Warnf("Cannot open CA file: %v", err) + // If there's an error reading the CA file, continue + // with nil certs and without the client connection + certs = nil + } } rpcc, err := chain.NewClient(activeNet.Params, cfg.RPCConnect, - cfg.BtcdUsername, cfg.BtcdPassword, certs) + cfg.BtcdUsername, cfg.BtcdPassword, certs, cfg.DisableClientTLS) if err != nil { log.Errorf("Cannot create chain server RPC client: %v", err) return diff --git a/chain/chain.go b/chain/chain.go index 1861dde..f89c9f4 100644 --- a/chain/chain.go +++ b/chain/chain.go @@ -51,7 +51,7 @@ type Client struct { quitMtx sync.Mutex } -func NewClient(net *btcnet.Params, connect, user, pass string, certs []byte) (*Client, error) { +func NewClient(net *btcnet.Params, connect, user, pass string, certs []byte, disableTLS bool) (*Client, error) { client := Client{ netParams: net, enqueueNotification: make(chan interface{}), @@ -76,6 +76,7 @@ func NewClient(net *btcnet.Params, connect, user, pass string, certs []byte) (*C Pass: pass, Certificates: certs, DisableConnectOnNew: true, + DisableTLS: disableTLS, } c, err := btcrpcclient.New(&conf, &ntfnCallbacks) if err != nil { diff --git a/config.go b/config.go index f11e008..bf72ef4 100644 --- a/config.go +++ b/config.go @@ -70,6 +70,7 @@ type config struct { RPCMaxClients int64 `long:"rpcmaxclients" description:"Max number of RPC clients for standard connections"` RPCMaxWebsockets int64 `long:"rpcmaxwebsockets" description:"Max number of RPC websocket connections"` DisableServerTLS bool `long:"noservertls" description:"Disable TLS for the RPC server -- NOTE: This is only allowed if the RPC server is bound to localhost"` + DisableClientTLS bool `long:"noclienttls" description:"Disable TLS for the RPC client -- NOTE: This is only allowed if the RPC client is connecting to localhost"` MainNet bool `long:"mainnet" description:"Use the main Bitcoin network (default testnet3)"` SimNet bool `long:"simnet" description:"Use the simulation test network (default testnet3)"` KeypoolSize uint `short:"k" long:"keypoolsize" description:"DEPRECATED -- Maximum number of addresses in keypool"` @@ -371,27 +372,32 @@ func loadConfig() (*config, []string, error) { "127.0.0.1": struct{}{}, "::1": struct{}{}, } - // If CAFile is unset, choose either the copy or local btcd cert. - if cfg.CAFile == "" { - cfg.CAFile = filepath.Join(cfg.DataDir, defaultCAFilename) + RPCHost, _, err := net.SplitHostPort(cfg.RPCConnect) + if err != nil { + return nil, nil, err + } + if cfg.DisableClientTLS { + if _, ok := localhostListeners[RPCHost]; !ok { + str := "%s: the --noclienttls option may not be used " + + "when connecting RPC to non localhost " + + "addresses: %s" + err := fmt.Errorf(str, funcName, cfg.RPCConnect) + fmt.Fprintln(os.Stderr, err) + fmt.Fprintln(os.Stderr, usageMessage) + return nil, nil, err + } + } else { + // If CAFile is unset, choose either the copy or local btcd cert. + if cfg.CAFile == "" { + cfg.CAFile = filepath.Join(cfg.DataDir, defaultCAFilename) - // If the CA copy does not exist, check if we're connecting to - // a local btcd and switch to its RPC cert if it exists. - if !fileExists(cfg.CAFile) { - host, _, err := net.SplitHostPort(cfg.RPCConnect) - if err != nil { - return nil, nil, err - } - switch host { - case "localhost": - fallthrough - - case "127.0.0.1": - fallthrough - - case "::1": - if fileExists(btcdHomedirCAFile) { - cfg.CAFile = btcdHomedirCAFile + // If the CA copy does not exist, check if we're connecting to + // a local btcd and switch to its RPC cert if it exists. + if !fileExists(cfg.CAFile) { + if _, ok := localhostListeners[RPCHost]; ok { + if fileExists(btcdHomedirCAFile) { + cfg.CAFile = btcdHomedirCAFile + } } } }