Line data Source code
1 : // Copyright (c) 2018-2022 The Bitcoin Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or http://www.opensource.org/licenses/mit-license.php. 4 : 5 : #include <chainparams.h> 6 : #include <common/run_command.h> 7 : #include <core_io.h> 8 : #include <psbt.h> 9 : #include <util/strencodings.h> 10 : #include <external_signer.h> 11 : 12 : #include <algorithm> 13 : #include <stdexcept> 14 : #include <string> 15 : #include <vector> 16 : 17 2 : ExternalSigner::ExternalSigner(const std::string& command, const std::string chain, const std::string& fingerprint, const std::string name): m_command(command), m_chain(chain), m_fingerprint(fingerprint), m_name(name) {} 18 2 : 19 0 : std::string ExternalSigner::NetworkArg() const 20 : { 21 0 : return " --chain " + m_chain; 22 : } 23 : 24 0 : bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, const std::string chain) 25 : { 26 : // Call <command> enumerate 27 2 : const UniValue result = RunCommandParseJSON(command + " enumerate"); 28 0 : if (!result.isArray()) { 29 0 : throw std::runtime_error(strprintf("'%s' received invalid response, expected array of signers", command)); 30 : } 31 0 : for (const UniValue& signer : result.getValues()) { 32 : // Check for error 33 0 : const UniValue& error = signer.find_value("error"); 34 0 : if (!error.isNull()) { 35 0 : if (!error.isStr()) { 36 0 : throw std::runtime_error(strprintf("'%s' error", command)); 37 : } 38 0 : throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr())); 39 : } 40 : // Check if fingerprint is present 41 0 : const UniValue& fingerprint = signer.find_value("fingerprint"); 42 0 : if (fingerprint.isNull()) { 43 0 : throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command)); 44 : } 45 0 : const std::string& fingerprintStr{fingerprint.get_str()}; 46 : // Skip duplicate signer 47 0 : bool duplicate = false; 48 0 : for (const ExternalSigner& signer : signers) { 49 0 : if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true; 50 : } 51 0 : if (duplicate) break; 52 0 : std::string name; 53 0 : const UniValue& model_field = signer.find_value("model"); 54 0 : if (model_field.isStr() && model_field.getValStr() != "") { 55 0 : name += model_field.getValStr(); 56 0 : } 57 0 : signers.push_back(ExternalSigner(command, chain, fingerprintStr, name)); 58 0 : } 59 : return true; 60 0 : } 61 : 62 0 : UniValue ExternalSigner::DisplayAddress(const std::string& descriptor) const 63 : { 64 0 : return RunCommandParseJSON(m_command + " --fingerprint \"" + m_fingerprint + "\"" + NetworkArg() + " displayaddress --desc \"" + descriptor + "\""); 65 0 : } 66 : 67 0 : UniValue ExternalSigner::GetDescriptors(const int account) 68 : { 69 0 : return RunCommandParseJSON(m_command + " --fingerprint \"" + m_fingerprint + "\"" + NetworkArg() + " getdescriptors --account " + strprintf("%d", account)); 70 0 : } 71 : 72 0 : bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::string& error) 73 : { 74 2 : // Serialize the PSBT 75 0 : CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); 76 0 : ssTx << psbtx; 77 : // parse ExternalSigner master fingerprint 78 0 : std::vector<unsigned char> parsed_m_fingerprint = ParseHex(m_fingerprint); 79 : // Check if signer fingerprint matches any input master key fingerprint 80 0 : auto matches_signer_fingerprint = [&](const PSBTInput& input) { 81 0 : for (const auto& entry : input.hd_keypaths) { 82 0 : if (parsed_m_fingerprint == MakeUCharSpan(entry.second.fingerprint)) return true; 83 : } 84 0 : for (const auto& entry : input.m_tap_bip32_paths) { 85 0 : if (parsed_m_fingerprint == MakeUCharSpan(entry.second.second.fingerprint)) return true; 86 : } 87 0 : return false; 88 0 : }; 89 : 90 0 : if (!std::any_of(psbtx.inputs.begin(), psbtx.inputs.end(), matches_signer_fingerprint)) { 91 0 : error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str()); 92 0 : return false; 93 : } 94 : 95 0 : const std::string command = m_command + " --stdin --fingerprint \"" + m_fingerprint + "\"" + NetworkArg(); 96 0 : const std::string stdinStr = "signtx \"" + EncodeBase64(ssTx.str()) + "\""; 97 : 98 0 : const UniValue signer_result = RunCommandParseJSON(command, stdinStr); 99 : 100 0 : if (signer_result.find_value("error").isStr()) { 101 0 : error = signer_result.find_value("error").get_str(); 102 0 : return false; 103 : } 104 : 105 0 : if (!signer_result.find_value("psbt").isStr()) { 106 0 : error = "Unexpected result from signer"; 107 0 : return false; 108 : } 109 : 110 0 : PartiallySignedTransaction signer_psbtx; 111 0 : std::string signer_psbt_error; 112 0 : if (!DecodeBase64PSBT(signer_psbtx, signer_result.find_value("psbt").get_str(), signer_psbt_error)) { 113 0 : error = strprintf("TX decode failed %s", signer_psbt_error); 114 0 : return false; 115 : } 116 : 117 0 : psbtx = signer_psbtx; 118 : 119 0 : return true; 120 0 : }