Line data Source code
1 : // Copyright (c) 2018-2021 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 0 : 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 : 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 0 : 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.emplace_back(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 : // 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 : return false; 85 0 : }; 86 : 87 0 : if (!std::any_of(psbtx.inputs.begin(), psbtx.inputs.end(), matches_signer_fingerprint)) { 88 0 : error = "Signer fingerprint " + m_fingerprint + " does not match any of the inputs:\n" + EncodeBase64(ssTx.str()); 89 0 : return false; 90 : } 91 : 92 0 : const std::string command = m_command + " --stdin --fingerprint " + m_fingerprint + NetworkArg(); 93 0 : const std::string stdinStr = "signtx " + EncodeBase64(ssTx.str()); 94 : 95 0 : const UniValue signer_result = RunCommandParseJSON(command, stdinStr); 96 : 97 0 : if (signer_result.find_value("error").isStr()) { 98 0 : error = signer_result.find_value("error").get_str(); 99 0 : return false; 100 : } 101 : 102 0 : if (!signer_result.find_value("psbt").isStr()) { 103 0 : error = "Unexpected result from signer"; 104 0 : return false; 105 : } 106 : 107 0 : PartiallySignedTransaction signer_psbtx; 108 0 : std::string signer_psbt_error; 109 0 : if (!DecodeBase64PSBT(signer_psbtx, signer_result.find_value("psbt").get_str(), signer_psbt_error)) { 110 0 : error = strprintf("TX decode failed %s", signer_psbt_error); 111 0 : return false; 112 : } 113 : 114 0 : psbtx = signer_psbtx; 115 : 116 0 : return true; 117 0 : }