From 7a22da98b9f81d206eb65d1fa4f5e773d888bac3 Mon Sep 17 00:00:00 2001 From: Guillaume Ballet Date: Fri, 31 May 2019 11:30:28 +0200 Subject: [PATCH] accounts/scwallet: flag to specify path to smartcard daemon (#19439) * accounts/scwallet: Add a switch to enable smartcard support * accounts: change the meaning of the switch * disable card support in windows until tested * only activate account if pcscd socket file is present * the switch is now the path to the socket file * accounts/scwallet: holiman's review feedback * accounts/scwallet: send the path to go-pcsclite * accounts/scwallet: add default, per platform path * accounts/scwallet: fix error log warning * accounts/scwallet: update pcsc lib to latest * accounts/scwallet: use default path from pcsclite * scwallet: forgot to change switch name * cmd: minor style cleanups (error handling first, then happy path) --- accounts/scwallet/hub.go | 4 +-- cmd/geth/main.go | 1 + cmd/geth/usage.go | 1 + cmd/utils/flags.go | 27 ++++++++++++++ node/config.go | 15 +++++--- .../github.com/gballet/go-libpcsclite/doc.go | 2 -- .../gballet/go-libpcsclite/doc_bsd.go | 35 +++++++++++++++++++ .../gballet/go-libpcsclite/doc_linux.go | 35 +++++++++++++++++++ .../gballet/go-libpcsclite/doc_windows.go | 35 +++++++++++++++++++ .../github.com/gballet/go-libpcsclite/msg.go | 10 ++++-- .../gballet/go-libpcsclite/winscard.go | 4 +-- vendor/vendor.json | 6 ++-- 12 files changed, 158 insertions(+), 17 deletions(-) create mode 100644 vendor/github.com/gballet/go-libpcsclite/doc_bsd.go create mode 100644 vendor/github.com/gballet/go-libpcsclite/doc_linux.go create mode 100644 vendor/github.com/gballet/go-libpcsclite/doc_windows.go diff --git a/accounts/scwallet/hub.go b/accounts/scwallet/hub.go index d1440cb96..5f939c658 100644 --- a/accounts/scwallet/hub.go +++ b/accounts/scwallet/hub.go @@ -152,8 +152,8 @@ func (hub *Hub) setPairing(wallet *Wallet, pairing *smartcardPairing) error { } // NewHub creates a new hardware wallet manager for smartcards. -func NewHub(scheme string, datadir string) (*Hub, error) { - context, err := pcsc.EstablishContext(pcsc.ScopeSystem) +func NewHub(daemonPath string, scheme string, datadir string) (*Hub, error) { + context, err := pcsc.EstablishContext(daemonPath, pcsc.ScopeSystem) if err != nil { return nil, err } diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 1b23cbd9f..d0a9bb08a 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -66,6 +66,7 @@ var ( utils.KeyStoreDirFlag, utils.ExternalSignerFlag, utils.NoUSBFlag, + utils.SmartCardDaemonPathFlag, utils.DashboardEnabledFlag, utils.DashboardAddrFlag, utils.DashboardPortFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 67b0027f2..4cc77b912 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -72,6 +72,7 @@ var AppHelpFlagGroups = []flagGroup{ utils.AncientFlag, utils.KeyStoreDirFlag, utils.NoUSBFlag, + utils.SmartCardDaemonPathFlag, utils.NetworkIdFlag, utils.TestnetFlag, utils.RinkebyFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 93d162370..7e19ebc0c 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -58,6 +58,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/netutil" "github.com/ethereum/go-ethereum/params" whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" + pcsclite "github.com/gballet/go-libpcsclite" cli "gopkg.in/urfave/cli.v1" ) @@ -129,6 +130,11 @@ var ( Name: "nousb", Usage: "Disables monitoring for and managing USB hardware wallets", } + SmartCardDaemonPathFlag = cli.StringFlag{ + Name: "pcscdpath", + Usage: "Path to the smartcard daemon (pcscd) socket file", + Value: pcsclite.PCSCDSockName, + } NetworkIdFlag = cli.Uint64Flag{ Name: "networkid", Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)", @@ -1126,6 +1132,7 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { setWS(ctx, cfg) setNodeUserIdent(ctx, cfg) setDataDir(ctx, cfg) + setSmartCard(ctx, cfg) if ctx.GlobalIsSet(ExternalSignerFlag.Name) { cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name) @@ -1145,6 +1152,26 @@ func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { } } +func setSmartCard(ctx *cli.Context, cfg *node.Config) { + // Skip enabling smartcards if no path is set + path := ctx.GlobalString(SmartCardDaemonPathFlag.Name) + if path == "" { + return + } + // Sanity check that the smartcard path is valid + fi, err := os.Stat(path) + if err != nil { + log.Error("Failed to verify smartcard daemon path", "path", path, "err", err) + return + } + if fi.Mode()&os.ModeType != os.ModeSocket { + log.Error("Invalid smartcard daemon path", "path", path, "type", fi.Mode().String()) + return + } + // Smartcard daemon path exists and is a socket, enable it + cfg.SmartCardDaemonPath = path +} + func setDataDir(ctx *cli.Context, cfg *node.Config) { switch { case ctx.GlobalIsSet(DataDirFlag.Name): diff --git a/node/config.go b/node/config.go index 43ee5ec21..d76311ba6 100644 --- a/node/config.go +++ b/node/config.go @@ -95,6 +95,9 @@ type Config struct { // NoUSB disables hardware wallet monitoring and connectivity. NoUSB bool `toml:",omitempty"` + // SmartCardDaemonPath is the path to the smartcard daemon's socket + SmartCardDaemonPath string `toml:",omitempty"` + // IPCPath is the requested location to place the IPC endpoint. If the path is // a simple file name, it is placed inside the data directory (or on the root // pipe path on Windows), whereas if it's a resolvable path name (absolute or @@ -505,11 +508,13 @@ func makeAccountManager(conf *Config) (*accounts.Manager, string, error) { backends = append(backends, trezorhub) } } - // Start a smart card hub - if schub, err := scwallet.NewHub(scwallet.Scheme, keydir); err != nil { - log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err)) - } else { - backends = append(backends, schub) + if len(conf.SmartCardDaemonPath) > 0 { + // Start a smart card hub + if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil { + log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err)) + } else { + backends = append(backends, schub) + } } } diff --git a/vendor/github.com/gballet/go-libpcsclite/doc.go b/vendor/github.com/gballet/go-libpcsclite/doc.go index d1085319a..0f28c0c9c 100644 --- a/vendor/github.com/gballet/go-libpcsclite/doc.go +++ b/vendor/github.com/gballet/go-libpcsclite/doc.go @@ -61,8 +61,6 @@ const ( SCardPowever = 0x0010 /* Card is powered */ SCardNegotiable = 0x0020 /* Ready for PTS */ SCardSpecific = 0x0040 /* PTS has been set */ - - PCSCDSockName = "/run/pcscd/pcscd.comm" ) // List of commands to send to the daemon diff --git a/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go b/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go new file mode 100644 index 000000000..ddec46c67 --- /dev/null +++ b/vendor/github.com/gballet/go-libpcsclite/doc_bsd.go @@ -0,0 +1,35 @@ +// BSD 3-Clause License +// +// Copyright (c) 2019, Guillaume Ballet +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build dragonfly darwin freebsd netbsd openbsd solaris + +package pcsc + +const PCSCDSockName string = "/var/run/pcscd/pcscd.comm" \ No newline at end of file diff --git a/vendor/github.com/gballet/go-libpcsclite/doc_linux.go b/vendor/github.com/gballet/go-libpcsclite/doc_linux.go new file mode 100644 index 000000000..becbf1677 --- /dev/null +++ b/vendor/github.com/gballet/go-libpcsclite/doc_linux.go @@ -0,0 +1,35 @@ +// BSD 3-Clause License +// +// Copyright (c) 2019, Guillaume Ballet +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build linux + +package pcsc + +const PCSCDSockName string = "/run/pcscd/pcscd.comm" \ No newline at end of file diff --git a/vendor/github.com/gballet/go-libpcsclite/doc_windows.go b/vendor/github.com/gballet/go-libpcsclite/doc_windows.go new file mode 100644 index 000000000..9bd6bd333 --- /dev/null +++ b/vendor/github.com/gballet/go-libpcsclite/doc_windows.go @@ -0,0 +1,35 @@ +// BSD 3-Clause License +// +// Copyright (c) 2019, Guillaume Ballet +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * Neither the name of the copyright holder nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// +build windows + +package pcsc + +const PCSCDSockName string = "" diff --git a/vendor/github.com/gballet/go-libpcsclite/msg.go b/vendor/github.com/gballet/go-libpcsclite/msg.go index 53f543530..1377082b1 100644 --- a/vendor/github.com/gballet/go-libpcsclite/msg.go +++ b/vendor/github.com/gballet/go-libpcsclite/msg.go @@ -62,7 +62,7 @@ func messageSendWithHeader(command uint32, conn net.Conn, data []byte) error { return err } -// ClientSetupSession prepares a communication channel for the client to talk to the server. +// clientSetupSession prepares a communication channel for the client to talk to the server. // This is called by the application to create a socket for local IPC with the // server. The socket is associated to the file \c PCSCLITE_CSOCK_NAME. /* @@ -73,6 +73,10 @@ func messageSendWithHeader(command uint32, conn net.Conn, data []byte) error { * @retval -1 The socket can not open a connection. * @retval -1 Can not set the socket to non-blocking. */ -func clientSetupSession() (net.Conn, error) { - return net.Dial("unix", PCSCDSockName) +func clientSetupSession(daemonPath string) (net.Conn, error) { + path := PCSCDSockName + if len(daemonPath) > 0 { + path = daemonPath + } + return net.Dial("unix", path) } diff --git a/vendor/github.com/gballet/go-libpcsclite/winscard.go b/vendor/github.com/gballet/go-libpcsclite/winscard.go index e4692ed16..b916db162 100644 --- a/vendor/github.com/gballet/go-libpcsclite/winscard.go +++ b/vendor/github.com/gballet/go-libpcsclite/winscard.go @@ -56,10 +56,10 @@ type Client struct { // EstablishContext asks the PCSC daemon to create a context // handle for further communication with connected cards and // readers. -func EstablishContext(scope uint32) (*Client, error) { +func EstablishContext(path string, scope uint32) (*Client, error) { client := &Client{} - conn, err := clientSetupSession() + conn, err := clientSetupSession(path) if err != nil { return nil, err } diff --git a/vendor/vendor.json b/vendor/vendor.json index b3e111800..a33a1d4e2 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -135,10 +135,10 @@ "revisionTime": "2018-04-18T12:24:29Z" }, { - "checksumSHA1": "GXqHzd0XkPLX/iulpOncaxbxzZo=", + "checksumSHA1": "+fiJGimxPPRSfi9sED4Lp6ytBeo=", "path": "github.com/gballet/go-libpcsclite", - "revision": "312b5175032f98274685a4dd81935a92ad2412a5", - "revisionTime": "2019-04-03T18:15:18Z" + "revision": "2fd9b619dd3c5d74acbd975f997a6441984d74a7", + "revisionTime": "2019-05-28T10:50:17Z" }, { "checksumSHA1": "gxV/cPPLkByTdY8y172t7v4qcZA=",