From b4d8f3617f18de9b7a1abdea68b873dd174021d4 Mon Sep 17 00:00:00 2001 From: Will O'Beirne Date: Fri, 4 May 2018 00:26:25 -0400 Subject: [PATCH] Message signing --- common/libs/wallet/deterministic/ledger.ts | 9 +++++++ shared/enclave/client/index.ts | 11 ++++++--- shared/enclave/server/handlers/index.ts | 4 +++- shared/enclave/server/handlers/signMessage.ts | 7 ++++++ .../server/handlers/signTransaction.ts | 2 +- shared/enclave/server/wallets/keepkey.ts | 10 +++++++- shared/enclave/server/wallets/ledger.ts | 16 ++++++++++--- shared/enclave/server/wallets/trezor.ts | 4 ++++ shared/enclave/types.ts | 24 ++++++++++++++++--- 9 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 shared/enclave/server/handlers/signMessage.ts diff --git a/common/libs/wallet/deterministic/ledger.ts b/common/libs/wallet/deterministic/ledger.ts index 0277cee2..f74dafaf 100644 --- a/common/libs/wallet/deterministic/ledger.ts +++ b/common/libs/wallet/deterministic/ledger.ts @@ -76,6 +76,15 @@ export class LedgerWallet extends HardwareWallet implements IFullWallet { // modeled after // https://github.com/kvhnuke/etherwallet/blob/3f7ff809e5d02d7ea47db559adaca1c930025e24/app/scripts/controllers/signMsgCtrl.js#L53 public async signMessage(msg: string): Promise { + if (process.env.BUILD_ELECTRON) { + const res = await EnclaveAPI.signMessage({ + walletType: WalletTypes.LEDGER, + message: msg, + path: this.getPath() + }); + return res.signedMessage; + } + const msgHex = Buffer.from(msg).toString('hex'); try { const signed = await this.ethApp.signPersonalMessage_async(this.getPath(), msgHex); diff --git a/shared/enclave/client/index.ts b/shared/enclave/client/index.ts index 5f603b2c..8aaf58ea 100644 --- a/shared/enclave/client/index.ts +++ b/shared/enclave/client/index.ts @@ -1,4 +1,3 @@ -import EthTx from 'ethereumjs-tx'; import { makeRequest } from './requests'; import { EnclaveMethods, @@ -7,7 +6,9 @@ import { GetChainCodeParams, GetChainCodeResponse, SignTransactionParams, - SignTransactionResponse + SignTransactionResponse, + SignMessageParams, + SignMessageResponse } from 'shared/enclave/types'; const api = { @@ -19,8 +20,12 @@ const api = { return makeRequest(EnclaveMethods.GET_CHAIN_CODE, params); }, - async signTransaction(params: SignTransactionParams) { + signTransaction(params: SignTransactionParams) { return makeRequest(EnclaveMethods.SIGN_TRANSACTION, params); + }, + + signMessage(params: SignMessageParams) { + return makeRequest(EnclaveMethods.SIGN_MESSAGE, params); } }; diff --git a/shared/enclave/server/handlers/index.ts b/shared/enclave/server/handlers/index.ts index ce61131d..856591bf 100644 --- a/shared/enclave/server/handlers/index.ts +++ b/shared/enclave/server/handlers/index.ts @@ -1,6 +1,7 @@ import getAddresses from './getAddresses'; import getChainCode from './getChainCode'; import signTransaction from './signTransaction'; +import signMessage from './signMessage'; import { EnclaveMethods, EnclaveMethodParams, EnclaveMethodResponse } from 'shared/enclave/types'; const handlers: { @@ -10,7 +11,8 @@ const handlers: { } = { [EnclaveMethods.GET_ADDRESSES]: getAddresses, [EnclaveMethods.GET_CHAIN_CODE]: getChainCode, - [EnclaveMethods.SIGN_TRANSACTION]: signTransaction + [EnclaveMethods.SIGN_TRANSACTION]: signTransaction, + [EnclaveMethods.SIGN_MESSAGE]: signMessage }; export default handlers; diff --git a/shared/enclave/server/handlers/signMessage.ts b/shared/enclave/server/handlers/signMessage.ts new file mode 100644 index 00000000..3fae6d56 --- /dev/null +++ b/shared/enclave/server/handlers/signMessage.ts @@ -0,0 +1,7 @@ +import { getWalletLib } from 'shared/enclave/server/wallets'; +import { SignMessageParams, SignMessageResponse } from 'shared/enclave/types'; + +export default function(params: SignMessageParams): Promise { + const wallet = getWalletLib(params.walletType); + return wallet.signMessage(params.message, params.path); +} diff --git a/shared/enclave/server/handlers/signTransaction.ts b/shared/enclave/server/handlers/signTransaction.ts index 3554103a..fbe1bc55 100644 --- a/shared/enclave/server/handlers/signTransaction.ts +++ b/shared/enclave/server/handlers/signTransaction.ts @@ -1,7 +1,7 @@ import { getWalletLib } from 'shared/enclave/server/wallets'; import { SignTransactionParams, SignTransactionResponse } from 'shared/enclave/types'; -export default function(params: SignTransactionParams): SignTransactionResponse { +export default function(params: SignTransactionParams): Promise { const wallet = getWalletLib(params.walletType); return wallet.signTransaction(params.transaction, params.path); } diff --git a/shared/enclave/server/wallets/keepkey.ts b/shared/enclave/server/wallets/keepkey.ts index be83de82..91ff0d01 100644 --- a/shared/enclave/server/wallets/keepkey.ts +++ b/shared/enclave/server/wallets/keepkey.ts @@ -2,7 +2,15 @@ import { WalletLib } from 'shared/enclave/types'; const KeepKey: WalletLib = { async getChainCode() { - throw new Error('Not yet supported'); + throw new Error('Not yet implemented'); + }, + + async signTransaction() { + throw new Error('Not yet implemented'); + }, + + async signMessage() { + throw new Error('Not yet implemented'); } }; diff --git a/shared/enclave/server/wallets/ledger.ts b/shared/enclave/server/wallets/ledger.ts index 165db0d9..52dbcd98 100644 --- a/shared/enclave/server/wallets/ledger.ts +++ b/shared/enclave/server/wallets/ledger.ts @@ -1,6 +1,6 @@ import EthTx from 'ethereumjs-tx'; import { addHexPrefix, toBuffer } from 'ethereumjs-util'; -import { WalletLib, RawTransaction } from 'shared/enclave/types'; +import { WalletLib } from 'shared/enclave/types'; import TransportNodeHid from '@ledgerhq/hw-transport-node-hid'; import LedgerEth from '@ledgerhq/hw-app-eth'; @@ -20,7 +20,7 @@ async function getEthApp() { } const Ledger: WalletLib = { - async getChainCode(dpath: string) { + async getChainCode(dpath) { const app = await getEthApp(); try { const res = await app.getAddress(dpath, false, true); @@ -33,7 +33,7 @@ const Ledger: WalletLib = { } }, - async signTransaction(tx: RawTransaction, path: string) { + async signTransaction(tx, path) { const app = await getEthApp(); const ethTx = new EthTx({ ...tx, @@ -52,6 +52,16 @@ const Ledger: WalletLib = { return { signedTransaction: signedTx.serialize().toString('hex') }; + }, + + async signMessage(msg: string, path: string) { + const app = await getEthApp(); + const msgHex = Buffer.from(msg).toString('hex'); + const signed = await app.signPersonalMessage(path, msgHex); + const combined = addHexPrefix(signed.r + signed.s + signed.v.toString(16)); + return { + signedMessage: combined + }; } }; diff --git a/shared/enclave/server/wallets/trezor.ts b/shared/enclave/server/wallets/trezor.ts index 1bf16295..2752d411 100644 --- a/shared/enclave/server/wallets/trezor.ts +++ b/shared/enclave/server/wallets/trezor.ts @@ -18,6 +18,10 @@ const Trezor: WalletLib = { async signTransaction() { throw new Error('Not yet implemented'); + }, + + async signMessage() { + throw new Error('Not yet implemented'); } }; diff --git a/shared/enclave/types.ts b/shared/enclave/types.ts index 51dd1cbc..e657be28 100644 --- a/shared/enclave/types.ts +++ b/shared/enclave/types.ts @@ -2,7 +2,8 @@ export enum EnclaveMethods { GET_ADDRESSES = 'get-addresses', GET_CHAIN_CODE = 'get-chain-code', - SIGN_TRANSACTION = 'sign-transaction' + SIGN_TRANSACTION = 'sign-transaction', + SIGN_MESSAGE = 'sign-message' } export enum WalletTypes { @@ -52,12 +53,28 @@ export interface SignTransactionResponse { signedTransaction: string; } +// Sign Message Request +export interface SignMessageParams { + walletType: WalletTypes; + message: string; + path: string; +} + +export interface SignMessageResponse { + signedMessage: string; +} + // All Requests & Responses -export type EnclaveMethodParams = GetAddressesParams | GetChainCodeParams | SignTransactionParams; +export type EnclaveMethodParams = + | GetAddressesParams + | GetChainCodeParams + | SignTransactionParams + | SignMessageParams; export type EnclaveMethodResponse = | GetAddressesResponse | GetChainCodeResponse - | SignTransactionResponse; + | SignTransactionResponse + | SignMessageResponse; // RPC requests, responses & failures export interface EnclaveSuccessResponse { @@ -82,4 +99,5 @@ export type EnclaveResponse = export interface WalletLib { getChainCode(dpath: string): Promise; signTransaction(transaction: RawTransaction, path: string): Promise; + signMessage(msg: string, path: string): Promise; }