diff --git a/README.md b/README.md index b9dd91e..6fb6452 100644 --- a/README.md +++ b/README.md @@ -123,8 +123,8 @@ the swap. Different tools may require different flags to use them with the supported wallet. For example, `btcatomicswap` includes flags for the RPC username and -password while `dcratomicswap` does not. Running a tool without any parameters -will show the full usage help. +password while `dcratomicswap` requires flags for TLS client authentication. +Running a tool without any parameters will show the full usage help. All of the tools support the same six commands. These commands are: @@ -295,7 +295,7 @@ expires, but should be saved in case a refund is necessary. _Party B runs:_ ``` -$ dcratomicswap --testnet participate TsfWDVTAcsLaHUhHnLLKkGnZuJz2vkmM6Vr 1.0 29c36b8dd380e0426bdc1d834e74a630bfd5d111 +$ dcratomicswap --testnet --clientcert=client.cert --clientkey=client.key participate TsfWDVTAcsLaHUhHnLLKkGnZuJz2vkmM6Vr 1.0 29c36b8dd380e0426bdc1d834e74a630bfd5d111 Passphrase: Contract fee: 0.000251 DCR (0.00100400 DCR/kB) @@ -346,7 +346,7 @@ reveals the secret to B, allowing B to withdraw from the Bitcoin contract. _Party A runs:_ ``` -$ dcratomicswap --testnet redeem 63a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a9149ee19833332a04d2be97b5c99c970191221c070c6704e6dabb59b17576a914b0ec0640c89cf803b8fdbd6e0183c354f71748c46888ac 010000000137afc6c25b027cb0a1db19a7aac365854796260c4c1077e3e8accae5e4c300e90300000001ffffffff02441455980100000000001976a9144d7c96b6d2360e48a07528332e537d81e068f8ba88ac00e1f50500000000000017a914195fb53333e61a415e9fda21bb991b38b5a4e1c387000000000000000001ffffffffffffffff00000000ffffffff6b483045022100b30971448c93be84c28b98ae159963e9521a84d0c3849821b6e8897d59cf4e6c0220228785cb8d1dba40752e4bd09d99b92b27bc3837b1c547f8b4ee8aba1dfec9310121035a12a086ecd1397f7f68146f4f251253b7c0092e167a1c92ff9e89cf96c68b5f 3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16 +$ dcratomicswap --testnet --clientcert=client.cert --clientkey=client.key redeem 63a61429c36b8dd380e0426bdc1d834e74a630bfd5d1118876a9149ee19833332a04d2be97b5c99c970191221c070c6704e6dabb59b17576a914b0ec0640c89cf803b8fdbd6e0183c354f71748c46888ac 010000000137afc6c25b027cb0a1db19a7aac365854796260c4c1077e3e8accae5e4c300e90300000001ffffffff02441455980100000000001976a9144d7c96b6d2360e48a07528332e537d81e068f8ba88ac00e1f50500000000000017a914195fb53333e61a415e9fda21bb991b38b5a4e1c387000000000000000001ffffffffffffffff00000000ffffffff6b483045022100b30971448c93be84c28b98ae159963e9521a84d0c3849821b6e8897d59cf4e6c0220228785cb8d1dba40752e4bd09d99b92b27bc3837b1c547f8b4ee8aba1dfec9310121035a12a086ecd1397f7f68146f4f251253b7c0092e167a1c92ff9e89cf96c68b5f 3e0b064c97247732a3b345ce7b2a835d928623cb2871c26db4c2539a38e61a16 Passphrase: Redeem fee: 0.000334 DCR (0.00100300 DCR/kB) diff --git a/cmd/dcratomicswap/go.mod b/cmd/dcratomicswap/go.mod index 764efae..aed5e3a 100644 --- a/cmd/dcratomicswap/go.mod +++ b/cmd/dcratomicswap/go.mod @@ -1,5 +1,7 @@ module github.com/decred/atomicswap/cmd/dcratomicswap +go 1.15 + require ( github.com/decred/dcrd/chaincfg v1.3.0 github.com/decred/dcrd/chaincfg/chainhash v1.0.1 diff --git a/cmd/dcratomicswap/main.go b/cmd/dcratomicswap/main.go index d7c5b90..c897f95 100644 --- a/cmd/dcratomicswap/main.go +++ b/cmd/dcratomicswap/main.go @@ -10,10 +10,13 @@ import ( "context" "crypto/rand" "crypto/sha256" + "crypto/tls" + "crypto/x509" "encoding/hex" "errors" "flag" "fmt" + "io/ioutil" "net" "os" "path/filepath" @@ -52,10 +55,12 @@ var ( ) var ( - flagset = flag.NewFlagSet("", flag.ExitOnError) - connectFlag = flagset.String("s", "localhost", "host[:port] of dcrwallet gRPC server") - certFlag = flagset.String("c", filepath.Join(dcrutil.AppDataDir("dcrwallet", false), "rpc.cert"), "dcrwallet RPC certificate path") - testnetFlag = flagset.Bool("testnet", false, "use testnet network") + flagset = flag.NewFlagSet("", flag.ExitOnError) + connectFlag = flagset.String("s", "localhost", "host[:port] of dcrwallet gRPC server") + certFlag = flagset.String("c", filepath.Join(dcrutil.AppDataDir("dcrwallet", false), "rpc.cert"), "dcrwallet RPC certificate path") + clientCertFlag = flagset.String("clientcert", "", "path to client authentication certificate") + clientKeyFlag = flagset.String("clientkey", "", "path to client authentication key") + testnetFlag = flagset.Bool("testnet", false, "use testnet network") ) // There are two directions that the atomic swap can be performed, as the @@ -346,15 +351,32 @@ func run() (err error, showUsage bool) { return cmd.runOfflineCommand(), false } + if *clientCertFlag == "" || *clientKeyFlag == "" { + return fmt.Errorf("-clientcert and -clientkey flags are required; see -h for usage"), false + } + connect, err := normalizeAddress(*connectFlag, walletPort(chainParams)) if err != nil { return fmt.Errorf("wallet server address: %v", err), true } - creds, err := credentials.NewClientTLSFromFile(*certFlag, "") + keypair, err := tls.LoadX509KeyPair(*clientCertFlag, *clientKeyFlag) + if err != nil { + return fmt.Errorf("open client keypair: %v", err), false + } + tc := &tls.Config{ + Certificates: []tls.Certificate{keypair}, + RootCAs: x509.NewCertPool(), + } + serverCAs, err := ioutil.ReadFile(*certFlag) if err != nil { - return fmt.Errorf("open certificate: %v", err), false + help := *certFlag == "" + return fmt.Errorf("cannot open server certificate: %v", err), help + } + if !tc.RootCAs.AppendCertsFromPEM(serverCAs) { + return fmt.Errorf("no certificates found in %q", *certFlag), false } + creds := credentials.NewTLS(tc) conn, err := grpc.Dial(connect, grpc.WithTransportCredentials(creds)) if err != nil { return fmt.Errorf("grpc dial: %v", err), false