Browse Source

fix proposal signature validation in publishTx

activeAddress
Ivan Socolsky 9 years ago
parent
commit
5f35aafc29
  1. 22
      lib/server.js
  2. 36
      test/integration/server.js

22
lib/server.js

@ -650,8 +650,8 @@ WalletService.prototype.joinWallet = function(opts, cb) {
} }
if (_.find(wallet.copayers, { if (_.find(wallet.copayers, {
xPubKey: opts.xPubKey xPubKey: opts.xPubKey
})) return cb(Errors.COPAYER_IN_WALLET); })) return cb(Errors.COPAYER_IN_WALLET);
if (wallet.copayers.length == wallet.n) return cb(Errors.WALLET_FULL); if (wallet.copayers.length == wallet.n) return cb(Errors.WALLET_FULL);
@ -744,8 +744,8 @@ WalletService.prototype._canCreateAddress = function(ignoreMaxGap, cb) {
isChange: true isChange: true
}), Defaults.MAX_MAIN_ADDRESS_GAP); }), Defaults.MAX_MAIN_ADDRESS_GAP);
if (latestAddresses.length < Defaults.MAX_MAIN_ADDRESS_GAP || _.any(latestAddresses, { if (latestAddresses.length < Defaults.MAX_MAIN_ADDRESS_GAP || _.any(latestAddresses, {
hasActivity: true hasActivity: true
})) return cb(null, true); })) return cb(null, true);
var bc = self._getBlockchainExplorer(latestAddresses[0].network); var bc = self._getBlockchainExplorer(latestAddresses[0].network);
var activityFound = false; var activityFound = false;
@ -1618,8 +1618,6 @@ WalletService.prototype._verifyRequestPubKey = function(requestPubKey, signature
* @param {Object} opts * @param {Object} opts
* @param {string} opts.txProposalId - The tx id. * @param {string} opts.txProposalId - The tx id.
* @param {string} opts.proposalSignature - S(raw tx). Used by other copayers to verify the proposal. * @param {string} opts.proposalSignature - S(raw tx). Used by other copayers to verify the proposal.
* @param {string} opts.proposalSignaturePubKey - (Optional) An alternative public key used to verify the proposal signature.
* @param {string} opts.proposalSignaturePubKeySig - (Optional) A signature used to validate the opts.proposalSignaturePubKey.
*/ */
WalletService.prototype.publishTx = function(opts, cb) { WalletService.prototype.publishTx = function(opts, cb) {
var self = this; var self = this;
@ -1648,13 +1646,11 @@ WalletService.prototype.publishTx = function(opts, cb) {
return cb(new ClientError('Invalid proposal signature')); return cb(new ClientError('Invalid proposal signature'));
} }
// Verify signingKey // Save signature info for other copayers to check
if (opts.proposalSignaturePubKey) { txp.proposalSignature = opts.proposalSignature;
if (opts.proposalSignaturePubKey != signingKey || if (signingKey.selfSigned) {
!self._verifyRequestPubKey(opts.proposalSignaturePubKey, opts.proposalSignaturePubKeySig, copayer.xPubKey) txp.proposalSignaturePubKey = signingKey.key;
) { txp.proposalSignaturePubKeySig = signingKey.signature;
return cb(new ClientError('Invalid proposal signing key'));
}
} }
// Verify UTXOs are still available // Verify UTXOs are still available

36
test/integration/server.js

@ -2739,6 +2739,7 @@ describe('Wallet service', function() {
server.getPendingTxs({}, function(err, txs) { server.getPendingTxs({}, function(err, txs) {
should.not.exist(err); should.not.exist(err);
txs.length.should.equal(1); txs.length.should.equal(1);
should.exist(txs[0].proposalSignature);
done(); done();
}); });
}); });
@ -2795,21 +2796,14 @@ describe('Wallet service', function() {
should.not.exist(err); should.not.exist(err);
should.exist(txp); should.exist(txp);
var raw = txp.getRawTx();
var proposalSignature = helpers.signMessage(raw, TestData.copayers[0].privKey_1H_0);
var pubKey = new Bitcore.PrivateKey(TestData.copayers[0].privKey_1H_0).toPublicKey().toString();
var pubKeySig = helpers.signMessage(pubKey, TestData.copayers[1].privKey_1H_0);
var publishOpts = { var publishOpts = {
txProposalId: txp.id, txProposalId: txp.id,
proposalSignature: proposalSignature, proposalSignature: helpers.signMessage(txp.getRawTx(), TestData.copayers[1].privKey_1H_0),
proposalSignaturePubKey: pubKey,
proposalSignaturePubKeySig: pubKeySig,
} }
server.publishTx(publishOpts, function(err) { server.publishTx(publishOpts, function(err) {
should.exist(err); should.exist(err);
err.message.should.contain('Invalid proposal signing key'); err.message.should.contain('Invalid proposal signature');
done(); done();
}); });
}); });
@ -2818,18 +2812,17 @@ describe('Wallet service', function() {
it('should accept a tx proposal signed with a custom key', function(done) { it('should accept a tx proposal signed with a custom key', function(done) {
var reqPrivKey = new Bitcore.PrivateKey(); var reqPrivKey = new Bitcore.PrivateKey();
var reqPubKey = reqPrivKey.toPublicKey(); var reqPubKey = reqPrivKey.toPublicKey().toString();
var xPrivKey = TestData.copayers[0].xPrivKey_44H_0H_0H; var xPrivKey = TestData.copayers[0].xPrivKey_44H_0H_0H;
var sig = helpers.signRequestPubKey(reqPubKey, xPrivKey);
var opts = { var accessOpts = {
copayerId: TestData.copayers[0].id44, copayerId: TestData.copayers[0].id44,
requestPubKey: reqPubKey, requestPubKey: reqPubKey,
signature: sig, signature: helpers.signRequestPubKey(reqPubKey, xPrivKey),
}; };
server.addAccess(opts, function(err) { server.addAccess(accessOpts, function(err) {
should.not.exist(err); should.not.exist(err);
helpers.stubUtxos(server, wallet, [1, 2], function() { helpers.stubUtxos(server, wallet, [1, 2], function() {
@ -2846,14 +2839,19 @@ describe('Wallet service', function() {
var publishOpts = { var publishOpts = {
txProposalId: txp.id, txProposalId: txp.id,
proposalSignature: helpers.signMessage(txp.getRawTx(), reqPrivKey), proposalSignature: helpers.signMessage(txp.getRawTx(), reqPrivKey),
proposalSignaturePubKey: reqPubKey,
proposalSignaturePubKeySig: sig,
} }
server.publishTx(publishOpts, function(err) { server.publishTx(publishOpts, function(err) {
should.exist(err); should.not.exist(err);
err.message.should.contain('Invalid proposal signing key'); server.getTx({
done(); txProposalId: txp.id
}, function(err, x) {
should.not.exist(err);
x.proposalSignature.should.equal(publishOpts.proposalSignature);
x.proposalSignaturePubKey.should.equal(accessOpts.requestPubKey);
x.proposalSignaturePubKeySig.should.equal(accessOpts.signature);
done();
});
}); });
}); });
}); });

Loading…
Cancel
Save