Skip to content

Commit

Permalink
Polycli KMS Ethereum Transaction Signing (#180)
Browse files Browse the repository at this point in the history
* feat: basic local signing functions

* feat: hacks on hacks - the creation of the gcp HSM key is working

* feat: adding working kms sign

* docs: updating

* docs: adding some basic usage notes

* fix: lints

* feat: make gen

* fix: generation versoin

* fix: make gen

* fix: minor comments and cleanup

* feat: adding list command

* feat: adding import

* fix: issue with listing versioned keys

* fix: elliptic lint

* chore: update kms signing docs

* docs: adding some docs for import

* docs: make gen-doc

---------

Co-authored-by: leovct <[email protected]>
  • Loading branch information
praetoriansentry and leovct authored Jan 5, 2024
1 parent d5fb815 commit a51b5e3
Show file tree
Hide file tree
Showing 20 changed files with 1,552 additions and 74 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ test: ## Run tests.
##@ Generation

.PHONY: gen
gen: gen-doc gen-proto gen-go-bindings gen-loadtest-modes gen-json-rpctypes ## Generate everything.
gen: gen-doc gen-proto gen-go-bindings gen-loadtest-modes gen-json-rpctypes ## Generate everything.

.PHONY: gen-doc
gen-doc: ## Generate documentation for `polycli`.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ Note: Do not modify this section! It is auto-generated by `cobra` using `make ge

- [polycli rpcfuzz](doc/polycli_rpcfuzz.md) - Continually run a variety of RPC calls and fuzzers.

- [polycli signer](doc/polycli_signer.md) - Utilities for security signing transactions

- [polycli version](doc/polycli_version.md) - Get the current version of this application

- [polycli wallet](doc/polycli_wallet.md) - Create or inspect BIP39(ish) wallets.
Expand Down
7 changes: 2 additions & 5 deletions cmd/parseethwallet/parseethwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/maticnetwork/polygon-cli/gethkeystore"
"io"
"os"
"strings"
Expand All @@ -27,10 +28,6 @@ var (
inputKeyStoreDirectory *string
)

type plainKeyJSON struct {
Address string `json:"address"`
Crypto keystore.CryptoJSON `json:"crypto"`
}
type outKey struct {
Address string
PublicKey string
Expand Down Expand Up @@ -60,7 +57,7 @@ var ParseETHWalletCmd = &cobra.Command{
if err != nil {
return err
}
k := new(plainKeyJSON)
k := new(gethkeystore.RawKeystoreData)
err = json.Unmarshal(rawData, &k)
if err != nil {
return err
Expand Down
5 changes: 3 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"fmt"
"os"

"github.com/maticnetwork/polygon-cli/cmd/dbbench"

"github.com/maticnetwork/polygon-cli/cmd/fork"
"github.com/maticnetwork/polygon-cli/cmd/p2p"
"github.com/maticnetwork/polygon-cli/cmd/parseethwallet"
Expand All @@ -15,6 +13,7 @@ import (
"github.com/spf13/viper"

"github.com/maticnetwork/polygon-cli/cmd/abi"
"github.com/maticnetwork/polygon-cli/cmd/dbbench"
"github.com/maticnetwork/polygon-cli/cmd/dumpblocks"
"github.com/maticnetwork/polygon-cli/cmd/enr"
"github.com/maticnetwork/polygon-cli/cmd/fund"
Expand All @@ -26,6 +25,7 @@ import (
"github.com/maticnetwork/polygon-cli/cmd/nodekey"
"github.com/maticnetwork/polygon-cli/cmd/rpc"
"github.com/maticnetwork/polygon-cli/cmd/rpcfuzz"
"github.com/maticnetwork/polygon-cli/cmd/signer"
"github.com/maticnetwork/polygon-cli/cmd/version"
"github.com/maticnetwork/polygon-cli/cmd/wallet"
)
Expand Down Expand Up @@ -121,6 +121,7 @@ func NewPolycliCommand() *cobra.Command {
parseethwallet.ParseETHWalletCmd,
rpc.RpcCmd,
rpcfuzz.RPCFuzzCmd,
signer.SignerCmd,
version.VersionCmd,
wallet.WalletCmd,
)
Expand Down
18 changes: 18 additions & 0 deletions cmd/signer/createCmdUsage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
The create subcommand will create a new key pair. By default, a hex private key will be written to `stdout`.
```bash
polycli signer create > private-key.txt
```

If you need to work with a go-ethereum style keystore, a key can be added by setting a `--keystore` directory. When you run this command, you'll need to specify a password to encrypt the private key.

```bash
polycli signer create --keystore /tmp/keystore
```

Polycli also has basic support for KMS with GCP. Creating a new key in the cloud can be accomplished with a command like this

```bash
# polycli assumes that there is default login that's been done already
gcloud auth application-default login
polycli signer create --kms GCP --gcp-project-id prj-polygonlabs-devtools-dev --key-id jhilliard-trash
```
25 changes: 25 additions & 0 deletions cmd/signer/importCmdUsage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
It's possible to import a simple hex encoded private key into a local
keystore or as a crypto key version in GCP KMS.

In order to import into a local keystore, a command like this could be used:

```bash
polycli signer import --keystore /tmp/keystore --private-key cf42d151cec45693f2ac1201e803b056c5f9e2e5d1af627ce41ab3b6faceda25
```

### Importing into GCP KMS

Importing into GCP KMS is a little bit more complicated. In order to run the import, a command like this would be used:

```bash
polycli signer import --private-key 42b6e34dc21598a807dc19d7784c71b2a7a01f6480dc6f58258f78e539f1a1fa --kms gcp --gcp-project-id prj-polygonlabs-devtools-dev --key-id jhilliard-code-quality --gcp-import-job-id test-import-job
```

There are a few things going on here:

1. We're specifying a `--private-key` that's hex encoded. That's the only format that `import` accepts at this time.
2. We're using `--kms gcp` which tell polycli that we want to use gcp kms as our backend
3. W've specifed `--gcp-project-id` which names a test project that we're using. We've left out `--gcp-location` and `--gcp-keyring-id` which means we're using the defaults.
4. We've set `--gcp-import-job-id test-import-job` which names a job that will be used to import the key. Basically GCP will give us a public key that we use to encrypt our key for importing

The `--key-id` is also important. This will set the name of the key that's going to be imported. Note, the key-id must have already been created in order for import to work. When we're doing the import, we're actually importing a new version of the key that already exists. For the time being, the `signer import` command will not create the first version of the key for you.
11 changes: 11 additions & 0 deletions cmd/signer/listCmdUsage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
After creating a few keys in the keystore or KMS, it's useful just to be able to list the keys. If you're using a keystore, the accounts can be listed using this command:

```bash
polycli signer list --keystore /tmp/keystore
```

In the case of GCP KMS, the keyring will need to be provided and the keys can be listed with this command:

```bash
polycli signer list --kms GCP --gcp-project-id prj-polygonlabs-devtools-dev --gcp-keyring-id polycli-keyring
```
75 changes: 75 additions & 0 deletions cmd/signer/signCmdUsage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
Currently, polycli only supports signing transactions. Message and arbitrary signing might happen in the future. In order to sign as message we first need to create some transaction data in a JSON file

```json
{
"from": "0xB41C20404dffA411fd3F5453a9EA4432Da64e70b",
"to": "0xB41C20404dffA411fd3F5453a9EA4432Da64e70b",
"gas": "0x8000",
"gasPrice": "0x30000000",
"maxFeePerGas": "0x30000000",
"maxPriorityFeePerGas": "0x30000000",
"value": "0x1",
"nonce": "0x0",

"input": "",

"chainId": "0x539",
"accessList": []
}
```

The file format here is defined by [`SendTxArgs`](https://pkg.go.dev/github.com/ethereum/[email protected]/signer/core/apitypes#SendTxArgs) in go-ethereum. This is a lower level transaction format and it will require you to manually specify things like `nonce` and `gasPrice`. In other libraries these are often computed for you.
The benefit here is that it gives us the ability to specify lower level options like `accessList` which aren't usually available in other libraries.

Assuming we have valid transaction data in `tx.json` we can sign the transaction three different ways depending on where our private key is stored

### Signing with Hex Key

This is the easiest, but least secure way to sign. In this case, we're providing a private key as a command line argument to polycli and using that to sign the transaction data. The signed transaction is written to `stdout`
```bash
polycli signer sign --private-key $(cat private-key.txt) --data-file tx.json --chain-id 1337 | jq '.'
```

This is the output that is generated. `signedTx` is the JSON formatted transaction which is readable but not readily usable. The `rawSignedTx` can be directly published.

```json
{
"rawSignedTx": "02f86c820539808430000000843000000082800094b41c20404dffa411fd3f5453a9ea4432da64e70b0180c080a0978b7e99d4941fddcbfc792632a53bd4ac4b690ae4395d8203ecec9836e53dd8a00e32626e8456afb6e59f1fb2a8835bd647a97fec4d9da6a46ecadbf310b345d6",
"signedTx": {
"type": "0x2",
"chainId": "0x539",
"nonce": "0x0",
"to": "0xb41c20404dffa411fd3f5453a9ea4432da64e70b",
"gas": "0x8000",
"gasPrice": null,
"maxPriorityFeePerGas": "0x30000000",
"maxFeePerGas": "0x30000000",
"value": "0x1",
"input": "0x",
"accessList": [],
"v": "0x0",
"r": "0x978b7e99d4941fddcbfc792632a53bd4ac4b690ae4395d8203ecec9836e53dd8",
"s": "0xe32626e8456afb6e59f1fb2a8835bd647a97fec4d9da6a46ecadbf310b345d6",
"yParity": "0x0",
"hash": "0xc03d220111f2d10b6a2b6b22c98e0e7e728a869cac0d3730e33b8bff683d677d"
}
}
```

### Signing with keystore

Signing with a keystore requires that you specify the `--keystore` location and the `--key-id` which in this case is the address of the key that you'd like to use for signing

```bash
polycli signer sign --keystore /tmp/keystore --key-id 0x58ce4bE73Ee7D0dee75395Ef662e98F91AD2E740 --data-file tx.json --chain-id 1337
```

### Signing with GCP KMS

The syntax for signing with KMS should look familiar.

```bash
# polycli assumes that there is default login that's been done already
gcloud auth application-default login
polycli signer sign --kms GCP --gcp-project-id prj-polygonlabs-devtools-dev --key-id jhilliard-trash --data-file tx.json --chain-id 1337
```
Loading

0 comments on commit a51b5e3

Please sign in to comment.