rpc/http/wallet: more aggressive validation for addrs/keys.

This commit is contained in:
Christopher Jeffrey 2017-02-28 14:49:50 -08:00
parent aa869e0b6a
commit 9f09de4867
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
10 changed files with 84 additions and 56 deletions

View File

@ -20,13 +20,14 @@ var HD = exports;
/**
* Instantiate an HD key (public or private) from an base58 string.
* @param {Base58String} xkey
* @param {Network?} network
* @returns {HDPrivateKey|HDPublicKey}
*/
HD.fromBase58 = function fromBase58(xkey) {
HD.fromBase58 = function fromBase58(xkey, network) {
if (HDPrivateKey.isBase58(xkey))
return HDPrivateKey.fromBase58(xkey);
return HDPublicKey.fromBase58(xkey);
return HDPrivateKey.fromBase58(xkey, network);
return HDPublicKey.fromBase58(xkey, network);
};
/**
@ -68,13 +69,14 @@ HD.fromMnemonic = function fromMnemonic(options, network) {
/**
* Instantiate an HD key from a jsonified key object.
* @param {Object} json - The jsonified transaction object.
* @param {Network?} network
* @returns {HDPrivateKey|HDPublicKey}
*/
HD.fromJSON = function fromJSON(json) {
HD.fromJSON = function fromJSON(json, network) {
if (json.xprivkey)
return HDPrivateKey.fromJSON(json);
return HDPublicKey.fromJSON(json);
return HDPrivateKey.fromJSON(json, network);
return HDPublicKey.fromJSON(json, network);
};
/**
@ -116,7 +118,7 @@ HD.from = function from(options, network) {
return options;
if (HD.isBase58(options))
return HD.fromBase58(options);
return HD.fromBase58(options, network);
if (HD.isRaw(options))
return HD.fromRaw(options);

View File

@ -615,11 +615,14 @@ HDPrivateKey.generate = function generate(network) {
* Inject properties from base58 key.
* @private
* @param {Base58String} xkey
* @param {Network?} network
*/
HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey) {
HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey, network) {
this.fromRaw(base58.decode(xkey));
this._xprivkey = xkey;
if (network && !this.verifyNetwork(network))
throw new Error('Network mismatch for HD private key.');
return this;
};
@ -813,11 +816,12 @@ HDPrivateKey.fromExtended = function fromExtended(data) {
/**
* Instantiate an HD private key from a base58 string.
* @param {Base58String} xkey
* @param {Network?} network
* @returns {HDPrivateKey}
*/
HDPrivateKey.fromBase58 = function fromBase58(xkey) {
return new HDPrivateKey().fromBase58(xkey);
HDPrivateKey.fromBase58 = function fromBase58(xkey, network) {
return new HDPrivateKey().fromBase58(xkey, network);
};
/**
@ -856,12 +860,13 @@ HDPrivateKey.prototype.toJSON = function toJSON() {
* Inject properties from json object.
* @private
* @param {Object} json
* @param {Network?} network
*/
HDPrivateKey.prototype.fromJSON = function fromJSON(json) {
HDPrivateKey.prototype.fromJSON = function fromJSON(json, network) {
assert(json.xprivkey, 'Could not handle key JSON.');
this.fromBase58(json.xprivkey);
this.fromBase58(json.xprivkey, network);
if (json.mnemonic)
this.mnemonic = Mnemonic.fromJSON(json.mnemonic);
@ -872,11 +877,12 @@ HDPrivateKey.prototype.fromJSON = function fromJSON(json) {
/**
* Instantiate an HDPrivateKey from a jsonified key object.
* @param {Object} json - The jsonified key object.
* @param {Network?} network
* @returns {HDPrivateKey}
*/
HDPrivateKey.fromJSON = function fromJSON(json) {
return new HDPrivateKey().fromJSON(json);
HDPrivateKey.fromJSON = function fromJSON(json, network) {
return new HDPrivateKey().fromJSON(json, network);
};
/**

View File

@ -409,22 +409,24 @@ HDPublicKey.prototype.toJSON = function toJSON() {
* Inject properties from json object.
* @private
* @param {Object} json
* @param {Network?} network
*/
HDPublicKey.prototype.fromJSON = function fromJSON(json) {
HDPublicKey.prototype.fromJSON = function fromJSON(json, network) {
assert(json.xpubkey, 'Could not handle HD key JSON.');
this.fromBase58(json.xpubkey);
this.fromBase58(json.xpubkey, network);
return this;
};
/**
* Instantiate an HDPrivateKey from a jsonified key object.
* Instantiate an HDPublicKey from a jsonified key object.
* @param {Object} json - The jsonified transaction object.
* @param {Network?} network
* @returns {HDPrivateKey}
*/
HDPublicKey.fromJSON = function fromJSON(json) {
return new HDPublicKey().fromJSON(json);
HDPublicKey.fromJSON = function fromJSON(json, network) {
return new HDPublicKey().fromJSON(json, network);
};
/**
@ -477,11 +479,14 @@ HDPublicKey.isRaw = function isRaw(data) {
* Inject properties from a base58 key.
* @private
* @param {Base58String} xkey
* @param {Network?} network
*/
HDPublicKey.prototype.fromBase58 = function fromBase58(xkey) {
HDPublicKey.prototype.fromBase58 = function fromBase58(xkey, network) {
this.fromRaw(base58.decode(xkey));
this._xpubkey = xkey;
if (network && !this.verifyNetwork(network))
throw new Error('Network mismatch for HD public key.');
return this;
};
@ -581,11 +586,12 @@ HDPublicKey.prototype.toRaw = function toRaw(network) {
/**
* Instantiate an HD public key from a base58 string.
* @param {Base58String} xkey
* @param {Network?} network
* @returns {HDPublicKey}
*/
HDPublicKey.fromBase58 = function fromBase58(xkey) {
return new HDPublicKey().fromBase58(xkey);
HDPublicKey.fromBase58 = function fromBase58(xkey, network) {
return new HDPublicKey().fromBase58(xkey, network);
};
/**

View File

@ -2055,7 +2055,7 @@ RPC.prototype._generatetoaddress = co(function* generatetoaddress(args, help) {
throw new RPCError('generatetoaddress numblocks address ( maxtries )');
numblocks = toNumber(args[0], 1);
address = Address.fromBase58(toString(args[1]));
address = Address.fromBase58(toString(args[1]), this.network);
return yield this._generateBlocks(numblocks, address);
});
@ -2137,7 +2137,7 @@ RPC.prototype.createrawtransaction = co(function* createrawtransaction(args, hel
continue;
}
address = Address.fromBase58(key);
address = Address.fromBase58(key, this.network);
b58 = address.toBase58(this.network);
if (addrs[b58])
@ -2270,7 +2270,7 @@ RPC.prototype._signrawtransaction = co(function* signrawtransaction(wallet, tx,
if (typeof secret !== 'string')
throw new RPCError('Invalid parameter');
key = KeyRing.fromSecret(secret);
key = KeyRing.fromSecret(secret, this.network);
keyMap[key.getPublicKey('hex')] = key;
keys.push(key);
}
@ -2375,7 +2375,7 @@ RPC.prototype.fundrawtransaction = co(function* fundrawtransaction(args, help) {
changeAddress = toString(options.changeAddress);
if (changeAddress)
changeAddress = Address.fromBase58(changeAddress);
changeAddress = Address.fromBase58(changeAddress, this.network);
feeRate = options.feeRate;
@ -2494,7 +2494,7 @@ RPC.prototype.validateaddress = co(function* validateaddress(args, help) {
b58 = toString(args[0]);
try {
address = Address.fromBase58(b58);
address = Address.fromBase58(b58, this.network);
} catch (e) {
return {
isvalid: false
@ -2561,7 +2561,7 @@ RPC.prototype.signmessagewithprivkey = co(function* signmessagewithprivkey(args,
key = toString(args[0]);
msg = toString(args[1]);
key = KeyRing.fromSecret(key);
key = KeyRing.fromSecret(key, this.network);
msg = new Buffer(RPC.magic + msg, 'utf8');
msg = crypto.hash256(msg);
@ -3242,7 +3242,7 @@ RPC.prototype.importprivkey = co(function* importprivkey(args, help) {
if (rescan && this.chain.options.prune)
throw new RPCError('Cannot rescan when pruned.');
key = KeyRing.fromSecret(secret);
key = KeyRing.fromSecret(secret, this.network);
yield wallet.importKey(0, key);
@ -3291,7 +3291,7 @@ RPC.prototype.importwallet = co(function* importwallet(args, help) {
if (parts.length < 4)
throw new RPCError('Malformed wallet.');
secret = KeyRing.fromSecret(parts[0]);
secret = KeyRing.fromSecret(parts[0], this.network);
time = +parts[1];
label = parts[2];
@ -3332,7 +3332,7 @@ RPC.prototype.importaddress = co(function* importaddress(args, help) {
if (rescan && this.chain.options.prune)
throw new RPCError('Cannot rescan when pruned.');
addr = Address.fromBase58(addr);
addr = Address.fromBase58(addr, this.network);
yield wallet.importAddress(0, addr);
@ -3888,7 +3888,7 @@ RPC.prototype.sendfrom = co(function* sendfrom(args, help) {
}
account = toString(args[0]);
address = Address.fromBase58(toString(args[1]));
address = Address.fromBase58(toString(args[1]), this.network);
amount = toSatoshi(args[2]);
if (!account)
@ -3940,7 +3940,7 @@ RPC.prototype.sendmany = co(function* sendmany(args, help) {
for (i = 0; i < keys.length; i++) {
key = keys[i];
value = toSatoshi(sendTo[key]);
address = Address.fromBase58(key);
address = Address.fromBase58(key, this.network);
hash = address.getHash('hex');
if (uniq[hash])
@ -3976,7 +3976,7 @@ RPC.prototype.sendtoaddress = co(function* sendtoaddress(args, help) {
+ ' subtractfeefromamount )');
}
address = Address.fromBase58(toString(args[0]));
address = Address.fromBase58(toString(args[0]), this.network);
amount = toSatoshi(args[1]);
subtractFee = toBool(args[4]);

View File

@ -345,7 +345,7 @@ HTTPServer.prototype._init = function _init() {
if (params.accountKey) {
enforce(typeof params.accountKey === 'string',
'accountKey must be a string.');
options.accountKey = HD.fromBase58(params.accountKey);
options.accountKey = HD.fromBase58(params.accountKey, this.network);
}
if (params.timeout != null) {
@ -371,9 +371,7 @@ HTTPServer.prototype._init = function _init() {
if (output.address) {
enforce(typeof output.address === 'string',
'Address must be a string.');
output.address = Address.fromBase58(output.address);
enforce(output.address.verifyNetwork(this.network),
'Wrong network for address.');
output.address = Address.fromBase58(output.address, this.network);
} else if (output.script) {
enforce(typeof output.script === 'string',
'Script must be a string.');
@ -396,13 +394,13 @@ HTTPServer.prototype._init = function _init() {
for (i = 0; i < params.address.length; i++) {
address = params.address[i];
enforce(typeof address === 'string', 'Address must be a string.');
address = Address.fromBase58(address);
address = Address.fromBase58(address, this.network);
options.address.push(address);
}
} else {
enforce(typeof params.address === 'string',
'Address must be a string.');
options.address = Address.fromBase58(params.address);
options.address = Address.fromBase58(params.address, this.network);
}
}
@ -439,7 +437,7 @@ HTTPServer.prototype._init = function _init() {
if (params.privateKey) {
enforce(typeof params.privateKey === 'string', 'Key must be a string.');
options.privateKey = KeyRing.fromSecret(params.privateKey);
options.privateKey = KeyRing.fromSecret(params.privateKey, this.network);
}
if (params.publicKey) {
@ -450,7 +448,7 @@ HTTPServer.prototype._init = function _init() {
if (params.master) {
enforce(typeof params.master === 'string', 'Key must be a string.');
options.master = HD.fromBase58(params.master);
options.master = HD.fromBase58(params.master, this.network);
}
if (params.mnemonic) {

View File

@ -284,23 +284,31 @@ Address.fromRaw = function fromRaw(data) {
* Inject properties from base58 address.
* @private
* @param {Base58Address} data
* @param {Network?} network
* @throws Parse error
*/
Address.prototype.fromBase58 = function fromBase58(data) {
Address.prototype.fromBase58 = function fromBase58(data, network) {
assert(typeof data === 'string');
return this.fromRaw(base58.decode(data));
this.fromRaw(base58.decode(data));
if (network && !this.verifyNetwork(network))
throw new Error('Network mismatch for address.');
return this;
};
/**
* Create an address object from a base58 address.
* @param {Base58Address} address
* @param {Network?} network
* @returns {Address}
* @throws Parse error.
*/
Address.fromBase58 = function fromBase58(address) {
return new Address().fromBase58(address);
Address.fromBase58 = function fromBase58(address, network) {
return new Address().fromBase58(address, network);
};
/**

View File

@ -323,9 +323,10 @@ KeyRing.prototype.toSecret = function toSecret() {
* Inject properties from serialized CBitcoinSecret.
* @private
* @param {Base58String} secret
* @param {Network?} network
*/
KeyRing.prototype.fromSecret = function fromSecret(data) {
KeyRing.prototype.fromSecret = function fromSecret(data, network) {
var br = new BufferReader(base58.decode(data), true);
var i, prefix, version, type, key, compressed;
@ -351,17 +352,23 @@ KeyRing.prototype.fromSecret = function fromSecret(data) {
br.verifyChecksum();
return this.fromPrivate(key, compressed, type);
this.fromPrivate(key, compressed, type);
if (network && !this.verifyNetwork(network))
throw new Error('Network mismatch for WIF.');
return this;
};
/**
* Instantiate a keyring from a serialized CBitcoinSecret.
* @param {Base58String} secret
* @param {Network?} network
* @returns {KeyRing}
*/
KeyRing.fromSecret = function fromSecret(data) {
return new KeyRing().fromSecret(data);
KeyRing.fromSecret = function fromSecret(data, network) {
return new KeyRing().fromSecret(data, network);
};
/**

View File

@ -280,7 +280,7 @@ Account.prototype.pushKey = function pushKey(key) {
var index;
if (HD.isBase58(key))
key = HD.fromBase58(key);
key = HD.fromBase58(key, this.network);
assert(key.verifyNetwork(this.network),
'Network mismatch for account key.');
@ -320,7 +320,7 @@ Account.prototype.pushKey = function pushKey(key) {
Account.prototype.spliceKey = function spliceKey(key) {
if (HD.isBase58(key))
key = HD.fromBase58(key);
key = HD.fromBase58(key, this.network);
assert(key.verifyNetwork(this.network),
'Network mismatch for account key.');

View File

@ -111,7 +111,7 @@ Wallet.prototype.fromOptions = function fromOptions(options) {
key = HD.fromMnemonic(null, this.network);
if (HD.isBase58(key))
key = HD.fromBase58(key);
key = HD.fromBase58(key, this.network);
assert(HD.isPrivate(key),
'Must create wallet with hd private key.');
@ -697,7 +697,7 @@ Wallet.prototype._createAccount = co(function* createAccount(options, passphrase
key = options.accountKey;
if (HD.isBase58(key))
key = HD.fromBase58(key);
key = HD.fromBase58(key, this.network);
if (!HD.isPublic(key))
throw new Error('Must add HD public keys to watch only wallet.');

View File

@ -106,11 +106,12 @@ WalletKey.fromScript = function fromScript(key, script, compressed, network) {
/**
* Instantiate a wallet key from a serialized CBitcoinSecret.
* @param {Base58String} secret
* @param {Network?} network
* @returns {WalletKey}
*/
WalletKey.fromSecret = function fromSecret(data) {
return new WalletKey().fromSecret(data);
WalletKey.fromSecret = function fromSecret(data, network) {
return new WalletKey().fromSecret(data, network);
};
/**