Merge bitcoin/bitcoin#25013: Remove cs_main from verifymessage, move msg utils to new file

fa60169811d6991a116bd37e1ff58049d2beee77 rpc: Move signmessage RPC util to new file (MacroFake)
fa9425177e6be2c53fb5c1333636fa4d678ab401 Remove cs_main from verifymessage (MacroFake)

Pull request description:

  The `verifymessage` RPC has several issues:

  * It takes `cs_main` for no reason, blocking progress on removing the `cs_main` global mutex.
  * It is located in a file called `misc`, which is not a very helpful name.

  Fix all issues.

ACKs for top commit:
  vincenzopalazzo:
    ACK fa60169811

Tree-SHA512: c71a1f481b828e0a544405fecbbc7ca44e66ea46b498d7aed1f1c584d6a99724deb13e89d90b9d5cdeecbce293e6a41e9f7ae299543f6d761bf9e7a839b6c7f3
This commit is contained in:
fanquake 2022-04-29 12:07:01 +01:00
commit 91ac12be44
No known key found for this signature in database
GPG Key ID: 2EEB9F5CC09526C1
5 changed files with 122 additions and 96 deletions

View File

@ -38,7 +38,11 @@ if [ "${RUN_TIDY}" = "true" ]; then
export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/src/"
CI_EXEC run-clang-tidy "${MAKEJOBS}"
export P_CI_DIR="${BASE_BUILD_DIR}/bitcoin-$HOST/"
CI_EXEC "python3 ${BASE_SCRATCH_DIR}/iwyu/include-what-you-use/iwyu_tool.py src/compat src/init -p . ${MAKEJOBS} -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp"
CI_EXEC "python3 ${BASE_SCRATCH_DIR}/iwyu/include-what-you-use/iwyu_tool.py"\
" src/compat"\
" src/init"\
" src/rpc/signmessage.cpp"\
" -p . ${MAKEJOBS} -- -Xiwyu --cxx17ns -Xiwyu --mapping_file=${BASE_BUILD_DIR}/bitcoin-$HOST/contrib/devtools/iwyu/bitcoin.core.imp"
fi
if [ "$RUN_SECURITY_TESTS" = "true" ]; then

View File

@ -386,6 +386,7 @@ libbitcoin_node_a_SOURCES = \
rpc/rawtransaction.cpp \
rpc/server.cpp \
rpc/server_util.cpp \
rpc/signmessage.cpp \
rpc/txoutproof.cpp \
script/sigcache.cpp \
shutdown.cpp \

View File

@ -14,14 +14,13 @@
#include <key_io.h>
#include <node/context.h>
#include <outputtype.h>
#include <rpc/blockchain.h>
#include <rpc/server.h>
#include <rpc/server_util.h>
#include <rpc/util.h>
#include <scheduler.h>
#include <script/descriptor.h>
#include <univalue.h>
#include <util/check.h>
#include <util/message.h> // For MessageSign(), MessageVerify()
#include <util/strencodings.h>
#include <util/syscall_sandbox.h>
#include <util/system.h>
@ -33,8 +32,6 @@
#include <malloc.h>
#endif
#include <univalue.h>
using node::NodeContext;
static RPCHelpMan validateaddress()
@ -311,95 +308,6 @@ static RPCHelpMan deriveaddresses()
};
}
static RPCHelpMan verifymessage()
{
return RPCHelpMan{"verifymessage",
"Verify a signed message.",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the signature."},
{"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature provided by the signer in base 64 encoding (see signmessage)."},
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."},
},
RPCResult{
RPCResult::Type::BOOL, "", "If the signature is verified or not."
},
RPCExamples{
"\nUnlock the wallet for 30 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n"
+ HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
LOCK(cs_main);
std::string strAddress = request.params[0].get_str();
std::string strSign = request.params[1].get_str();
std::string strMessage = request.params[2].get_str();
switch (MessageVerify(strAddress, strSign, strMessage)) {
case MessageVerificationResult::ERR_INVALID_ADDRESS:
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
case MessageVerificationResult::ERR_ADDRESS_NO_KEY:
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
case MessageVerificationResult::ERR_MALFORMED_SIGNATURE:
throw JSONRPCError(RPC_TYPE_ERROR, "Malformed base64 encoding");
case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
case MessageVerificationResult::ERR_NOT_SIGNED:
return false;
case MessageVerificationResult::OK:
return true;
}
return false;
},
};
}
static RPCHelpMan signmessagewithprivkey()
{
return RPCHelpMan{"signmessagewithprivkey",
"\nSign a message with the private key of an address\n",
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."},
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
},
RPCResult{
RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
},
RPCExamples{
"\nCreate the signature\n"
+ HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::string strPrivkey = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
CKey key = DecodeSecret(strPrivkey);
if (!key.IsValid()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
}
std::string signature;
if (!MessageSign(key, strMessage, signature)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
}
return signature;
},
};
}
static RPCHelpMan setmocktime()
{
return RPCHelpMan{"setmocktime",
@ -799,8 +707,6 @@ void RegisterMiscRPCCommands(CRPCTable& t)
{"util", &createmultisig},
{"util", &deriveaddresses},
{"util", &getdescriptorinfo},
{"util", &verifymessage},
{"util", &signmessagewithprivkey},
{"util", &getindexinfo},
{"hidden", &setmocktime},
{"hidden", &mockscheduler},

View File

@ -16,6 +16,7 @@ void RegisterNetRPCCommands(CRPCTable &tableRPC);
void RegisterMiscRPCCommands(CRPCTable &tableRPC);
void RegisterMiningRPCCommands(CRPCTable &tableRPC);
void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
void RegisterSignMessageRPCCommands(CRPCTable&);
void RegisterSignerRPCCommands(CRPCTable &tableRPC);
static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
@ -27,6 +28,7 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
RegisterMiscRPCCommands(t);
RegisterMiningRPCCommands(t);
RegisterRawTransactionRPCCommands(t);
RegisterSignMessageRPCCommands(t);
#ifdef ENABLE_EXTERNAL_SIGNER
RegisterSignerRPCCommands(t);
#endif // ENABLE_EXTERNAL_SIGNER

113
src/rpc/signmessage.cpp Normal file
View File

@ -0,0 +1,113 @@
// Copyright (c) 2010 Satoshi Nakamoto
// Copyright (c) 2009-2022 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <key.h>
#include <key_io.h>
#include <rpc/protocol.h>
#include <rpc/request.h>
#include <rpc/server.h>
#include <rpc/util.h>
#include <univalue.h>
#include <util/message.h>
#include <string>
static RPCHelpMan verifymessage()
{
return RPCHelpMan{"verifymessage",
"Verify a signed message.",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the signature."},
{"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature provided by the signer in base 64 encoding (see signmessage)."},
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."},
},
RPCResult{
RPCResult::Type::BOOL, "", "If the signature is verified or not."
},
RPCExamples{
"\nUnlock the wallet for 30 seconds\n"
+ HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
"\nCreate the signature\n"
+ HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::string strAddress = request.params[0].get_str();
std::string strSign = request.params[1].get_str();
std::string strMessage = request.params[2].get_str();
switch (MessageVerify(strAddress, strSign, strMessage)) {
case MessageVerificationResult::ERR_INVALID_ADDRESS:
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
case MessageVerificationResult::ERR_ADDRESS_NO_KEY:
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
case MessageVerificationResult::ERR_MALFORMED_SIGNATURE:
throw JSONRPCError(RPC_TYPE_ERROR, "Malformed base64 encoding");
case MessageVerificationResult::ERR_PUBKEY_NOT_RECOVERED:
case MessageVerificationResult::ERR_NOT_SIGNED:
return false;
case MessageVerificationResult::OK:
return true;
}
return false;
},
};
}
static RPCHelpMan signmessagewithprivkey()
{
return RPCHelpMan{"signmessagewithprivkey",
"\nSign a message with the private key of an address\n",
{
{"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key to sign the message with."},
{"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
},
RPCResult{
RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
},
RPCExamples{
"\nCreate the signature\n"
+ HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
"\nVerify the signature\n"
+ HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
"\nAs a JSON-RPC call\n"
+ HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
},
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
{
std::string strPrivkey = request.params[0].get_str();
std::string strMessage = request.params[1].get_str();
CKey key = DecodeSecret(strPrivkey);
if (!key.IsValid()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
}
std::string signature;
if (!MessageSign(key, strMessage, signature)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Sign failed");
}
return signature;
},
};
}
void RegisterSignMessageRPCCommands(CRPCTable& t)
{
static const CRPCCommand commands[]{
{"util", &verifymessage},
{"util", &signmessagewithprivkey},
};
for (const auto& c : commands) {
t.appendCommand(c.name, &c);
}
}