195 lines
No EOL
6.8 KiB
JavaScript
195 lines
No EOL
6.8 KiB
JavaScript
'use strict';
|
|
|
|
angular.module('copayApp.services')
|
|
.factory('intelTEE', function($log, $timeout, gettext, lodash, bitcore, hwWallet, bwcService, platformInfo) {
|
|
|
|
var root = {};
|
|
|
|
root.description = {
|
|
supported: platformInfo.supportsIntelTEE,
|
|
version: platformInfo.versionIntelTEE,
|
|
id: 'intelTEE',
|
|
name: 'Intel TEE',
|
|
longName: 'Intel TEE Hardware Wallet',
|
|
derivationStrategy: 'BIP44',
|
|
isEmbeddedHardware: true,
|
|
supportsTestnet: true
|
|
};
|
|
|
|
if (!root.description.supported) {
|
|
return root;
|
|
}
|
|
|
|
var IntelWallet = require('intelWalletCon');
|
|
var TEE_APP_ID = '63279de1b6cb4dcf8c206716bd318092f8c206716bd31809263279de1b6cb4dc';
|
|
|
|
root.walletEnclave = new IntelWallet.Wallet();
|
|
var walletEnclaveStatus = root.walletEnclave.initializeEnclave();
|
|
if (walletEnclaveStatus != 0) {
|
|
$log.error('Failed to create Intel Wallet enclave');
|
|
}
|
|
|
|
root.getInfoForNewWallet = function(isMultisig, account, networkName, callback) {
|
|
var opts = {};
|
|
initSource(opts, function(err, opts) {
|
|
if (err) return callback(err);
|
|
|
|
root.getEntropySource(opts.hwInfo.id, isMultisig, account, function(err, entropySource) {
|
|
if (err) return callback(err);
|
|
|
|
opts.entropySource = entropySource;
|
|
root.getXPubKey(opts.hwInfo.id, hwWallet.getAddressPath(root.description.id, isMultisig, account, networkName), function(data) {
|
|
if (!data.success) {
|
|
$log.warn(data.message);
|
|
return callback(data);
|
|
}
|
|
opts.extendedPublicKey = data.xpubkey;
|
|
opts.externalSource = root.description.id;
|
|
opts.derivationStrategy = root.description.derivationStrategy;
|
|
|
|
return callback(null, opts);
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
root.getXPubKey = function(teeWalletId, path, callback) {
|
|
$log.debug('TEE deriving xPub path:', path);
|
|
|
|
// Expected to be a extended public key.
|
|
var xpubkey = root.walletEnclave.getPublicKey(teeWalletId, path);
|
|
|
|
// Error messages returned in value.
|
|
var result = {
|
|
success: false,
|
|
message: xpubkey.ExtendedPublicKey
|
|
};
|
|
|
|
// Success indicated by status being equal to the tee wallet id.
|
|
if (xpubkey.Status == teeWalletId) {
|
|
result.success = true;
|
|
result.message = 'OK';
|
|
result.xpubkey = xpubkey.ExtendedPublicKey;
|
|
} else {
|
|
$log.error('Failed to get xpubkey from TEE wallet: ' + result.message);
|
|
}
|
|
|
|
callback(result);
|
|
};
|
|
|
|
root.getEntropySource = function(teeWalletId, isMultisig, account, callback) {
|
|
root.getXPubKey(teeWalletId, hwWallet.getEntropyPath(root.description.id, isMultisig, account), function(data) {
|
|
if (!data.success)
|
|
return callback(hwWallet._err(data));
|
|
|
|
return callback(null, hwWallet.pubKeyToEntropySource(data.xpubkey));
|
|
});
|
|
};
|
|
|
|
root.showMneumonic = function(teeWalletId, cb) {
|
|
var result = root.walletEnclave.displayWordList(teeWalletId, 'en');
|
|
if (result != teeWalletId) {
|
|
cb(result);
|
|
} else {
|
|
cb();
|
|
}
|
|
};
|
|
|
|
root.showReceiveAddress = function(teeWalletId, address, cb) {
|
|
var isMultisig = false; // TODO
|
|
var account = 0; // TODO
|
|
var basePath = hwWallet.getAddressPath(root.description.id, isMultisig, account, address.network);
|
|
var keyPath = address.path.replace('m', basePath);
|
|
|
|
var result = root.walletEnclave.displayReceiveAddress(teeWalletId, keyPath);
|
|
if (result != teeWalletId) {
|
|
cb(result);
|
|
} else {
|
|
cb();
|
|
}
|
|
};
|
|
|
|
root.signTx = function(teeWalletId, txp, callback) {
|
|
var account = 0; // TODO
|
|
var isMultisig = txp.requiredSignatures > 1;
|
|
var basePath = hwWallet.getAddressPath(root.description.id, isMultisig, account, txp.network);
|
|
|
|
var rawTx = bwcService.Client.getRawTx(txp);
|
|
var keypaths = lodash.map(lodash.pluck(txp.inputs, 'path'), function(path) {
|
|
return path.replace('m', basePath);
|
|
});
|
|
var publicKeys = lodash.pluck(txp.inputs, 'publicKeys');
|
|
var changePublicKeys = txp.changeAddress.publicKeys;
|
|
publicKeys.push(changePublicKeys);
|
|
|
|
var changeaddrpath;
|
|
if (txp.changeAddress) {
|
|
changeaddrpath = txp.changeAddress.path.replace('m', basePath);
|
|
}
|
|
|
|
var result;
|
|
if (txp.requiredSignatures == 1) {
|
|
result = root.walletEnclave.signTransaction(teeWalletId, rawTx, changeaddrpath, keypaths);
|
|
} else {
|
|
result = root.walletEnclave.signTransaction(teeWalletId, rawTx, changeaddrpath, keypaths, publicKeys, txp.requiredSignatures, changePublicKeys, txp.requiredSignatures);
|
|
}
|
|
|
|
if (result.Status != teeWalletId) {
|
|
return callback('TEE failed to sign transction: ' + result.Status);
|
|
}
|
|
return callback(null, result);
|
|
};
|
|
|
|
function initSource(opts, callback) {
|
|
var args = {
|
|
"Testnet" : (opts.networkName == 'livenet'? false : true),
|
|
"PINUnlockRequired" : false,
|
|
"PINSignatureDataRequired" : false,
|
|
"PINSignatureTransaction" : 0,
|
|
"ExportCount" : 10,
|
|
"MaxPINAttempts" : 3,
|
|
"PINTimeout" : 30
|
|
};
|
|
|
|
var teeStatus = root.walletEnclave.createWallet(TEE_APP_ID, args);
|
|
switch (teeStatus) {
|
|
case "CREATE WALLET FAILURE":
|
|
case "CREATE WALLET FAILED TO INITIALIZE":
|
|
case "CREATE WALLET FAILURE BAD INPUT":
|
|
case "CREATE WALLET FAILURE case SERIALIZATION":
|
|
case "DELETE_WALLET_AUTHORIZATION_UNSUCCESSFUL":
|
|
case "LOAD_WALLET_FAILTURE":
|
|
case "IMPORT WORD LIST FAILTURE":
|
|
case "IMPORT WORD LIST FAILURE BAD INPUT":
|
|
case "IMPORT WORD NOT IN DICTIONARY":
|
|
case "INVALID PIN":
|
|
case "INVALID APPLICATION ID":
|
|
case "DISPLAY WORD LIST FAILURE":
|
|
case "DELETE WALLET NO SUCH APPLICATION ID":
|
|
case "SIGN DATA FAILURE":
|
|
case "SIGN DATA INVALID HASH":
|
|
case "SIGN DATA BUFFER TOO SMALL":
|
|
case "SIGN DATA INVALID PIN":
|
|
case "RECEIVE ADDRESS INVALID INPUT":
|
|
case "RECEIVE ADDRESS NULL":
|
|
case "RECEIVE ADDRESS BUFFER TOO SMALL":
|
|
case "PUBLIC KEY BUFFER TOO SMALL":
|
|
case "LOAD WALLET FAILURE":
|
|
case "PUBLIC KEY FAILURE":
|
|
case "PUBLIC KEY FAIL TO SERIALIZE":
|
|
case "UKNOWN ERROR CODE":
|
|
$log.error(teeStatus);
|
|
return callback(teeStatus); // TODO: translate error text for display
|
|
break;
|
|
default:
|
|
opts.hwInfo = {
|
|
name: root.description.id,
|
|
id: teeStatus
|
|
};
|
|
$log.debug('TEE wallet created: ' + opts.hwInfo.id);
|
|
return callback(null, opts);
|
|
}
|
|
};
|
|
|
|
return root;
|
|
}); |