Error when trying to sign using a watch-only wallet

The cli wallet was correctly refusing to sign, but the RPC wallet (and
wallet2 internally) allowed it and would sign with the all-0s address,
which of course is invalid and fails to verify.  This now throws if
attempting to do so to get an error returned to the rpc endpoint.

Other minor changes here:
- make wallet2::verify static (verification doesn't depend on the wallet
  instance at all).
- Add documentation for wallet2 sign/verify
- Slight DRY of wallet2::sign
This commit is contained in:
Jason Rhinelander 2020-11-23 21:15:35 -04:00
parent b6a83a49a5
commit a842e3df74
3 changed files with 30 additions and 7 deletions

View File

@ -13049,20 +13049,20 @@ void wallet2::set_account_tag_description(const std::string& tag, const std::str
std::string wallet2::sign(std::string_view data, cryptonote::subaddress_index index) const
{
if (m_watch_only)
throw std::logic_error{"Unable to sign with a watch-only wallet"};
crypto::hash hash;
crypto::cn_fast_hash(data.data(), data.size(), hash);
const cryptonote::account_keys &keys = m_account.get_keys();
crypto::signature signature;
crypto::secret_key skey;
crypto::secret_key skey = keys.m_spend_secret_key;
crypto::public_key pkey;
if (index.is_zero())
{
skey = keys.m_spend_secret_key;
pkey = keys.m_account_address.m_spend_public_key;
}
else
{
skey = keys.m_spend_secret_key;
crypto::secret_key m = m_account.get_device().get_subaddress_secret_key(keys.m_view_secret_key, index);
sc_add((unsigned char*)&skey, (unsigned char*)&m, (unsigned char*)&skey);
secret_key_to_public_key(skey, pkey);
@ -13073,7 +13073,7 @@ std::string wallet2::sign(std::string_view data, cryptonote::subaddress_index in
return result;
}
bool wallet2::verify(std::string_view data, const cryptonote::account_public_address &address, std::string_view signature) const
bool wallet2::verify(std::string_view data, const cryptonote::account_public_address &address, std::string_view signature)
{
if (!tools::starts_with(signature, SIG_MAGIC)) {
LOG_PRINT_L0("Signature header check error");

View File

@ -1107,8 +1107,28 @@ private:
*/
void set_account_tag_description(const std::string& tag, const std::string& description);
/*!
* \brief Signs an arbitrary string using the wallet's secret spend key.
*
* \param data the data to sign
* \param index the subaccount/subaddress indices to use (if omitted: use main address)
*
* \return the signature.
*
* \throw std::logic_error if called on a view-only wallet.
*/
std::string sign(std::string_view data, cryptonote::subaddress_index index = {0, 0}) const;
bool verify(std::string_view data, const cryptonote::account_public_address &address, std::string_view signature) const;
/*!
* \brief Verifies a signed string.
*
* \param data - the data that has been signed.
* \param address - the public address of the wallet that signed the data.
* \param signature - the signature itself.
*
* \return true if the signature verified successfully, false if verification failed.
*/
static bool verify(std::string_view data, const cryptonote::account_public_address &address, std::string_view signature);
/*!
* \brief sign_multisig_participant signs given message with the multisig public signer key

View File

@ -1695,6 +1695,9 @@ namespace tools
SIGN::response wallet_rpc_server::invoke(SIGN::request&& req)
{
require_open();
if (m_wallet->watch_only())
throw wallet_rpc_error{error_code::WATCH_ONLY, "Unable to sign a value using a watch-only wallet."};
SIGN::response res{};
res.signature = m_wallet->sign(req.data, {req.account_index, req.address_index});