Message signing

This commit is contained in:
Will O'Beirne 2018-05-04 00:26:25 -04:00
parent b9bd734cd0
commit b4d8f3617f
No known key found for this signature in database
GPG Key ID: 44C190DB5DEAF9F6
9 changed files with 75 additions and 12 deletions

View File

@ -76,6 +76,15 @@ export class LedgerWallet extends HardwareWallet implements IFullWallet {
// modeled after // modeled after
// https://github.com/kvhnuke/etherwallet/blob/3f7ff809e5d02d7ea47db559adaca1c930025e24/app/scripts/controllers/signMsgCtrl.js#L53 // https://github.com/kvhnuke/etherwallet/blob/3f7ff809e5d02d7ea47db559adaca1c930025e24/app/scripts/controllers/signMsgCtrl.js#L53
public async signMessage(msg: string): Promise<string> { public async signMessage(msg: string): Promise<string> {
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'); const msgHex = Buffer.from(msg).toString('hex');
try { try {
const signed = await this.ethApp.signPersonalMessage_async(this.getPath(), msgHex); const signed = await this.ethApp.signPersonalMessage_async(this.getPath(), msgHex);

View File

@ -1,4 +1,3 @@
import EthTx from 'ethereumjs-tx';
import { makeRequest } from './requests'; import { makeRequest } from './requests';
import { import {
EnclaveMethods, EnclaveMethods,
@ -7,7 +6,9 @@ import {
GetChainCodeParams, GetChainCodeParams,
GetChainCodeResponse, GetChainCodeResponse,
SignTransactionParams, SignTransactionParams,
SignTransactionResponse SignTransactionResponse,
SignMessageParams,
SignMessageResponse
} from 'shared/enclave/types'; } from 'shared/enclave/types';
const api = { const api = {
@ -19,8 +20,12 @@ const api = {
return makeRequest<GetChainCodeResponse>(EnclaveMethods.GET_CHAIN_CODE, params); return makeRequest<GetChainCodeResponse>(EnclaveMethods.GET_CHAIN_CODE, params);
}, },
async signTransaction(params: SignTransactionParams) { signTransaction(params: SignTransactionParams) {
return makeRequest<SignTransactionResponse>(EnclaveMethods.SIGN_TRANSACTION, params); return makeRequest<SignTransactionResponse>(EnclaveMethods.SIGN_TRANSACTION, params);
},
signMessage(params: SignMessageParams) {
return makeRequest<SignMessageResponse>(EnclaveMethods.SIGN_MESSAGE, params);
} }
}; };

View File

@ -1,6 +1,7 @@
import getAddresses from './getAddresses'; import getAddresses from './getAddresses';
import getChainCode from './getChainCode'; import getChainCode from './getChainCode';
import signTransaction from './signTransaction'; import signTransaction from './signTransaction';
import signMessage from './signMessage';
import { EnclaveMethods, EnclaveMethodParams, EnclaveMethodResponse } from 'shared/enclave/types'; import { EnclaveMethods, EnclaveMethodParams, EnclaveMethodResponse } from 'shared/enclave/types';
const handlers: { const handlers: {
@ -10,7 +11,8 @@ const handlers: {
} = { } = {
[EnclaveMethods.GET_ADDRESSES]: getAddresses, [EnclaveMethods.GET_ADDRESSES]: getAddresses,
[EnclaveMethods.GET_CHAIN_CODE]: getChainCode, [EnclaveMethods.GET_CHAIN_CODE]: getChainCode,
[EnclaveMethods.SIGN_TRANSACTION]: signTransaction [EnclaveMethods.SIGN_TRANSACTION]: signTransaction,
[EnclaveMethods.SIGN_MESSAGE]: signMessage
}; };
export default handlers; export default handlers;

View File

@ -0,0 +1,7 @@
import { getWalletLib } from 'shared/enclave/server/wallets';
import { SignMessageParams, SignMessageResponse } from 'shared/enclave/types';
export default function(params: SignMessageParams): Promise<SignMessageResponse> {
const wallet = getWalletLib(params.walletType);
return wallet.signMessage(params.message, params.path);
}

View File

@ -1,7 +1,7 @@
import { getWalletLib } from 'shared/enclave/server/wallets'; import { getWalletLib } from 'shared/enclave/server/wallets';
import { SignTransactionParams, SignTransactionResponse } from 'shared/enclave/types'; import { SignTransactionParams, SignTransactionResponse } from 'shared/enclave/types';
export default function(params: SignTransactionParams): SignTransactionResponse { export default function(params: SignTransactionParams): Promise<SignTransactionResponse> {
const wallet = getWalletLib(params.walletType); const wallet = getWalletLib(params.walletType);
return wallet.signTransaction(params.transaction, params.path); return wallet.signTransaction(params.transaction, params.path);
} }

View File

@ -2,7 +2,15 @@ import { WalletLib } from 'shared/enclave/types';
const KeepKey: WalletLib = { const KeepKey: WalletLib = {
async getChainCode() { 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');
} }
}; };

View File

@ -1,6 +1,6 @@
import EthTx from 'ethereumjs-tx'; import EthTx from 'ethereumjs-tx';
import { addHexPrefix, toBuffer } from 'ethereumjs-util'; 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 TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
import LedgerEth from '@ledgerhq/hw-app-eth'; import LedgerEth from '@ledgerhq/hw-app-eth';
@ -20,7 +20,7 @@ async function getEthApp() {
} }
const Ledger: WalletLib = { const Ledger: WalletLib = {
async getChainCode(dpath: string) { async getChainCode(dpath) {
const app = await getEthApp(); const app = await getEthApp();
try { try {
const res = await app.getAddress(dpath, false, true); 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 app = await getEthApp();
const ethTx = new EthTx({ const ethTx = new EthTx({
...tx, ...tx,
@ -52,6 +52,16 @@ const Ledger: WalletLib = {
return { return {
signedTransaction: signedTx.serialize().toString('hex') 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
};
} }
}; };

View File

@ -18,6 +18,10 @@ const Trezor: WalletLib = {
async signTransaction() { async signTransaction() {
throw new Error('Not yet implemented'); throw new Error('Not yet implemented');
},
async signMessage() {
throw new Error('Not yet implemented');
} }
}; };

View File

@ -2,7 +2,8 @@
export enum EnclaveMethods { export enum EnclaveMethods {
GET_ADDRESSES = 'get-addresses', GET_ADDRESSES = 'get-addresses',
GET_CHAIN_CODE = 'get-chain-code', GET_CHAIN_CODE = 'get-chain-code',
SIGN_TRANSACTION = 'sign-transaction' SIGN_TRANSACTION = 'sign-transaction',
SIGN_MESSAGE = 'sign-message'
} }
export enum WalletTypes { export enum WalletTypes {
@ -52,12 +53,28 @@ export interface SignTransactionResponse {
signedTransaction: string; signedTransaction: string;
} }
// Sign Message Request
export interface SignMessageParams {
walletType: WalletTypes;
message: string;
path: string;
}
export interface SignMessageResponse {
signedMessage: string;
}
// All Requests & Responses // All Requests & Responses
export type EnclaveMethodParams = GetAddressesParams | GetChainCodeParams | SignTransactionParams; export type EnclaveMethodParams =
| GetAddressesParams
| GetChainCodeParams
| SignTransactionParams
| SignMessageParams;
export type EnclaveMethodResponse = export type EnclaveMethodResponse =
| GetAddressesResponse | GetAddressesResponse
| GetChainCodeResponse | GetChainCodeResponse
| SignTransactionResponse; | SignTransactionResponse
| SignMessageResponse;
// RPC requests, responses & failures // RPC requests, responses & failures
export interface EnclaveSuccessResponse<T = EnclaveMethodResponse> { export interface EnclaveSuccessResponse<T = EnclaveMethodResponse> {
@ -82,4 +99,5 @@ export type EnclaveResponse<T = EnclaveMethodResponse> =
export interface WalletLib { export interface WalletLib {
getChainCode(dpath: string): Promise<GetChainCodeResponse>; getChainCode(dpath: string): Promise<GetChainCodeResponse>;
signTransaction(transaction: RawTransaction, path: string): Promise<SignTransactionResponse>; signTransaction(transaction: RawTransaction, path: string): Promise<SignTransactionResponse>;
signMessage(msg: string, path: string): Promise<SignMessageResponse>;
} }