Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: deduplicate the message sign/verify code #17577

Merged
merged 3 commits into from Feb 25, 2020

Conversation

vasild
Copy link
Contributor

@vasild vasild commented Nov 24, 2019

The message signing and verifying logic was replicated in a few places
in the code. Consolidate in a newly introduced MessageSign() and
MessageVerify() and add unit tests for them.

@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 24, 2019

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

src/util/message.cpp Outdated Show resolved Hide resolved
@fanquake
Copy link
Member

Looks like this is going to overlap with #17557.

@vasild

This comment has been minimized.

@vasild
Copy link
Contributor Author

vasild commented Nov 29, 2019

@jkczyz What do you think about this PR and its relation to #17557? Merge both in one PR?

@jkczyz
Copy link
Contributor

jkczyz commented Dec 4, 2019

@jkczyz What do you think about this PR and its relation to #17557? Merge both in one PR?

I have #17557 based on an outstanding PR (#17399), though I suppose it didn't have to be. The former resulted from a comment in the latter. I deliberately kept the change small so it could hopefully be merged quicker. Though I wanted to add a test to clarify why the "magic" string is needed.

That said, from a design perspective, I prefer your PR as it hides the complexity around signing a message.

@vasild
Copy link
Contributor Author

vasild commented Dec 7, 2019

@jkczyz thanks for the feedback! I did cherry-pick the last two commits from #17557 into this PR under e3d85bc - the hashing utility function and the unit test for it (to clarify why the "magic" string is needed).

@vasild
Copy link
Contributor Author

vasild commented Dec 7, 2019

Conflicts

Reviewers, this pull request conflicts with the following ones:

* [#17593](https://drahtbot.github.io/bitcoin_core_issue_redirect/r/17593.html) (test: move more utility functions into test utility library by mzumsande)

* [#17581](https://drahtbot.github.io/bitcoin_core_issue_redirect/r/17581.html) (refactor: Remove settings merge reverse precedence code by ryanofsky)

* [#17580](https://drahtbot.github.io/bitcoin_core_issue_redirect/r/17580.html) (refactor: Add ALLOW_LIST flags and enforce usage in CheckArgFlags by ryanofsky)

* [#17493](https://drahtbot.github.io/bitcoin_core_issue_redirect/r/17493.html) (util: Forbid ambiguous multiple assignments in config file by ryanofsky)

* [#17473](https://drahtbot.github.io/bitcoin_core_issue_redirect/r/17473.html) (refactor: Settings code cleanups by ryanofsky)

* [#17399](https://drahtbot.github.io/bitcoin_core_issue_redirect/r/17399.html) (validation: Templatize ValidationState instead of subclassing by jkczyz)

* [#16545](https://drahtbot.github.io/bitcoin_core_issue_redirect/r/16545.html) (refactor: Implement missing error checking for ArgsManager flags by ryanofsky)

All of the above conflicts are mechanical, small and easy to resolve.

@instagibbs
Copy link
Member

concept ACK, though I'd probably be more pedantic in calling it "Bitcoin Signed Message Protocol" or something. Unfortunately there's no BIP to refer to.

@vasild
Copy link
Contributor Author

vasild commented Dec 24, 2019

@instagibbs Thanks for the review! Where would you put the "Bitcoin Signed Message Protocol" label?

We do message signing and verification now. What about encryption and decryption? Would that be useful feature or just a bloat that is rarely used? If encryption may be added in the future then maybe just "Bitcoin Message Protocol" would be a better name, or "Bitcoin Text Message Protocol".

@laanwj
Copy link
Member

laanwj commented Feb 5, 2020

I don't think encryption / decryption in bitcoind is a good idea. It is best to avoid using keys for multiple purposes (e.g. use a signing key for encryption, and vice versa). Also it's scope creep: Bitcoin core is a validating full node. It should do that well, and not try to make a GPG-ish mess of it that tries to do everything with a mash-up of features but nothing particularly well…

@Sjors
Copy link
Member

Sjors commented Feb 12, 2020

See also @achow101's #18115

@vasild
Copy link
Contributor Author

vasild commented Feb 12, 2020

See also @achow101's #18115

@Sjors thanks for the notice!

This PR (#17577) deduplicates message signing and message verification code.

I peeked at #18115 and among other things it deduplicates the message signing code from 2 of 3 places and does not deduplicate the message verification code. Assuming it also fixes the 3rd place where message signing code is repeated, then it will achieve half of this PR.

Should #18115 hit master before this PR, then I will trim this PR to only consolidate the message verification code.

@vasild
Copy link
Contributor Author

vasild commented Feb 12, 2020

I peeked at #18115 and among other things it deduplicates the message signing code from 2 of 3 places and does not deduplicate the message verification code. Assuming it also fixes the 3rd place...

That was fixed and now #18115 deduplicates all 3 message signing repetitions.

MessageSign() from #17577 is equivalent to SignMessage() from #18115. The former has unit tests added in #17577.

Copy link
Member

@achow101 achow101 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couple of nits. otherwise ACK 1a00fb8


switch (MessageVerify(address, signature, message)) {
case MessageVerificationResult::ERR_INVALID_ADDRESS:
ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These ui->statusLabel_VM->setStyleSheet("QLabel { color: red; }");s could be moved out of the switch to further reduce duplication.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

bool MessageSign(
const CKey& privkey,
const std::string& message,
std::string* signature)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be a reference (std::string&) instead of pointer.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

const uint256 signature_hash = Hash(unsigned_tx.begin(), unsigned_tx.end());

const uint256 message_hash = MessageHash(unsigned_tx);
BOOST_CHECK_NE(message_hash, signature_hash);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you should have on additional check here with the full hashed message. i.e. also hash Bitcoin Signed Message:\n... and compare that with message_hash.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notice: assuming CHashWriter hasher(SER_GETHASH, 0);, then:

hasher << "ab" << "cd";

would produce a different result than:

hasher << "abcd";

@@ -14,7 +15,27 @@
#include <string>
#include <vector>

const std::string strMessageMagic = "Bitcoin Signed Message:\n";
static const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renaming this should probably go in the next commit?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@Sjors
Copy link
Member

Sjors commented Feb 13, 2020

tACK ad39c8f, thanks for adding tests as well

@achow101
Copy link
Member

I'm seeing a new compiler warning:

In file included from ./script/signingprovider.h:13,
                 from ./outputtype.h:10,
                 from rpc/misc.cpp:8:
rpc/misc.cpp: In function ‘UniValue verifymessage(const JSONRPCRequest&)’:
./sync.h:179:104: warning: control reaches end of non-void function [-Wreturn-type]
  179 | #define LOCK(cs) DebugLock<decltype(cs)> PASTE2(criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
      |                                                                                                        ^
rpc/misc.cpp:273:5: note: in expansion of macro ‘LOCK’
  273 |     LOCK(cs_main);
      |     ^~~~

case MessageVerificationResult::ERR_NOT_SIGNED:
return false;
case MessageVerificationResult::OK:
return true;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need another return false statement after this switch.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch. I'm not getting that -Wreturn-type warning on macOS. Only one of the Travis machines noticed it: https://travis-ci.org/bitcoin/bitcoin/jobs/649943882?utm_medium=notification&utm_source=github_status

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added return false;, thanks!

vasild and others added 3 commits February 14, 2020 10:45
The logic of verifying a message was duplicated in 2 places:

src/qt/signverifymessagedialog.cpp
  SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()

src/rpc/misc.cpp
  verifymessage()

with the only difference being the result handling. Move the logic into
a dedicated

src/util/message.cpp
  MessageVerify()

which returns a set of result codes, call it from the 2 places and just
handle the results differently in the callers.
The logic of signing a message was duplicated in 3 places:

src/qt/signverifymessagedialog.cpp
  SignVerifyMessageDialog::on_signMessageButton_SM_clicked()

src/rpc/misc.cpp
  signmessagewithprivkey()

src/wallet/rpcwallet.cpp
  signmessage()

Move the logic into

src/util/message.cpp
  MessageSign()

and call it from all the 3 places.
And add unit test for it.

The purpose of using a preamble or "magic" text as part of signing and
verifying a message was not given when the code was repeated in a few
locations. Make a test showing how it is used to prevent inadvertently
signing a transaction.
@Sjors
Copy link
Member

Sjors commented Feb 14, 2020

re-ACK e193a84

@achow101
Copy link
Member

ACK e193a84

maflcko pushed a commit that referenced this pull request Feb 16, 2020
…Travis machines

c98c26e ci: use --enable-werror on more hosts (Sjors Provoost)
6ba617d build: add Wreturn-type to Werror flags (Sjors Provoost)

Pull request description:

  I overlooked a missing `return false` in #17577 (comment) and the warning only showed up on one Travis machine (`warning: control reaches end of non-void function [-Wreturn-type]`).

  This PR promotes `Wreturn-type` to an error when configured with `--enable-werror`. I also added `--enable-werror` to the Travis machine that happened to catch this particular instance.

ACKs for top commit:
  vasild:
    ACK c98c26e.
  practicalswift:
    ACK c98c26e

Tree-SHA512: 64e86c67fef2c5048aab201a8400b7e4a6f27b93d626159ba0b2807b5f119d2b0a83e3372db88f692cb4b0d059722d6a642d130c74a4f991a27f3a6b21780b5f
@Sjors
Copy link
Member

Sjors commented Feb 19, 2020

@meshcollider some of this touches the wallet - and #18115 that builds on top of this definitely does - so maybe you can take a look?

@laanwj laanwj added this to Blockers in High-priority for review Feb 20, 2020
Copy link
Member

@instagibbs instagibbs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK e193a84

* @param[in] signature The signature in base64 format.
* @param[in] message The message that was signed.
* @return result code */
MessageVerificationResult MessageVerify(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I'd prefer actual types used instead of strings for all args.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a non-blocking comment :) let's get this merged

Copy link
Contributor

@meshcollider meshcollider left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK e193a84

Nice cleanup, thanks!

@meshcollider meshcollider merged commit 03f98b1 into bitcoin:master Feb 25, 2020
@vasild vasild deleted the message-dedup branch February 25, 2020 10:33
@meshcollider meshcollider removed this from Blockers in High-priority for review Feb 25, 2020
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Feb 25, 2020
e193a84 Refactor message hashing into a utility function (Jeffrey Czyz)
f8f0d98 Deduplicate the message signing code (Vasil Dimov)
2ce3447 Deduplicate the message verifying code (Vasil Dimov)

Pull request description:

  The message signing and verifying logic was replicated in a few places
  in the code. Consolidate in a newly introduced `MessageSign()` and
  `MessageVerify()` and add unit tests for them.

ACKs for top commit:
  Sjors:
    re-ACK e193a84
  achow101:
    ACK e193a84
  instagibbs:
    utACK bitcoin@e193a84
  meshcollider:
    utACK e193a84

Tree-SHA512: b0e02a7d4623a98c8f8c77627af1725e6df07700de4630c2f75da6beacdf55414c38ba147bc6d2a757491ab07c827dddf93e8632fe600478760e255714ddab88
jasonbcox pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Oct 24, 2020
Summary:
 * Deduplicate the message verifying code

The logic of verifying a message was duplicated in 2 places:

src/qt/signverifymessagedialog.cpp
  SignVerifyMessageDialog::on_verifyMessageButton_VM_clicked()

src/rpc/misc.cpp
  verifymessage()

with the only difference being the result handling. Move the logic into
a dedicated

src/util/message.cpp
  MessageVerify()

which returns a set of result codes, call it from the 2 places and just
handle the results differently in the callers.

 * Deduplicate the message signing code

The logic of signing a message was duplicated in 3 places:

src/qt/signverifymessagedialog.cpp
  SignVerifyMessageDialog::on_signMessageButton_SM_clicked()

src/rpc/misc.cpp
  signmessagewithprivkey()

src/wallet/rpcwallet.cpp
  signmessage()

Move the logic into

src/util/message.cpp
  MessageSign()

and call it from all the 3 places.

 * Refactor message hashing into a utility function

And add unit test for it.

The purpose of using a preamble or "magic" text as part of signing and
verifying a message was not given when the code was repeated in a few
locations. Make a test showing how it is used to prevent inadvertently
signing a transaction.

Backport of Core [[bitcoin/bitcoin#17577 | PR17577]]

Test Plan:
  ninja all check-all

Reviewers: #bitcoin_abc, majcosta

Reviewed By: #bitcoin_abc, majcosta

Subscribers: majcosta

Differential Revision: https://reviews.bitcoinabc.org/D8098
sidhujag pushed a commit to syscoin-core/syscoin that referenced this pull request Nov 10, 2020
e193a84 Refactor message hashing into a utility function (Jeffrey Czyz)
f8f0d98 Deduplicate the message signing code (Vasil Dimov)
2ce3447 Deduplicate the message verifying code (Vasil Dimov)

Pull request description:

  The message signing and verifying logic was replicated in a few places
  in the code. Consolidate in a newly introduced `MessageSign()` and
  `MessageVerify()` and add unit tests for them.

ACKs for top commit:
  Sjors:
    re-ACK e193a84
  achow101:
    ACK e193a84
  instagibbs:
    utACK bitcoin@e193a84
  meshcollider:
    utACK e193a84

Tree-SHA512: b0e02a7d4623a98c8f8c77627af1725e6df07700de4630c2f75da6beacdf55414c38ba147bc6d2a757491ab07c827dddf93e8632fe600478760e255714ddab88
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Feb 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

9 participants