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 32 : 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 10 : std::string ExternalSigner::NetworkArg() const 20 : { 21 10 : return " --chain " + m_chain; 22 : } 23 : 24 22 : bool ExternalSigner::Enumerate(const std::string& command, std::vector<ExternalSigner>& signers, const std::string chain) 25 : { 26 : // Call <command> enumerate 27 24 : const UniValue result = RunCommandParseJSON(command + " enumerate"); 28 16 : if (!result.isArray()) { 29 0 : throw std::runtime_error(strprintf("'%s' received invalid response, expected array of signers", command)); 30 : } 31 32 : for (const UniValue& signer : result.getValues()) { 32 : // Check for error 33 18 : const UniValue& error = signer.find_value("error"); 34 18 : if (!error.isNull()) { 35 2 : if (!error.isStr()) { 36 0 : throw std::runtime_error(strprintf("'%s' error", command)); 37 : } 38 2 : throw std::runtime_error(strprintf("'%s' error: %s", command, error.getValStr())); 39 : } 40 : // Check if fingerprint is present 41 16 : const UniValue& fingerprint = signer.find_value("fingerprint"); 42 16 : if (fingerprint.isNull()) { 43 0 : throw std::runtime_error(strprintf("'%s' received invalid response, missing signer fingerprint", command)); 44 : } 45 16 : const std::string& fingerprintStr = fingerprint.get_str(); 46 : // Skip duplicate signer 47 16 : bool duplicate = false; 48 18 : for (const ExternalSigner& signer : signers) { 49 2 : if (signer.m_fingerprint.compare(fingerprintStr) == 0) duplicate = true; 50 : } 51 16 : if (duplicate) break; 52 16 : std::string name; 53 16 : const UniValue& model_field = signer.find_value("model"); 54 16 : if (model_field.isStr() && model_field.getValStr() != "") { 55 16 : name += model_field.getValStr(); 56 16 : } 57 16 : signers.emplace_back(command, chain, fingerprintStr, name); 58 16 : } 59 : return true; 60 24 : } 61 : 62 2 : UniValue ExternalSigner::DisplayAddress(const std::string& descriptor) const 63 : { 64 2 : return RunCommandParseJSON(m_command + " --fingerprint " + m_fingerprint + NetworkArg() + " displayaddress --desc " + descriptor); 65 0 : } 66 : 67 4 : UniValue ExternalSigner::GetDescriptors(const int account) 68 : { 69 4 : return RunCommandParseJSON(m_command + " --fingerprint " + m_fingerprint + NetworkArg() + " getdescriptors --account " + strprintf("%d", account)); 70 0 : } 71 : 72 4 : bool ExternalSigner::SignTransaction(PartiallySignedTransaction& psbtx, std::string& error) 73 : { 74 : // Serialize the PSBT 75 4 : CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); 76 4 : ssTx << psbtx; 77 : // parse ExternalSigner master fingerprint 78 4 : std::vector<unsigned char> parsed_m_fingerprint = ParseHex(m_fingerprint); 79 : // Check if signer fingerprint matches any input master key fingerprint 80 8 : auto matches_signer_fingerprint = [&](const PSBTInput& input) { 81 4 : for (const auto& entry : input.hd_keypaths) { 82 4 : if (parsed_m_fingerprint == MakeUCharSpan(entry.second.fingerprint)) return true; 83 : } 84 0 : return false; 85 4 : }; 86 : 87 4 : 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 4 : const std::string command = m_command + " --stdin --fingerprint " + m_fingerprint + NetworkArg(); 93 4 : const std::string stdinStr = "signtx " + EncodeBase64(ssTx.str()); 94 : 95 4 : const UniValue signer_result = RunCommandParseJSON(command, stdinStr); 96 : 97 4 : if (signer_result.find_value("error").isStr()) { 98 0 : error = signer_result.find_value("error").get_str(); 99 0 : return false; 100 : } 101 : 102 4 : if (!signer_result.find_value("psbt").isStr()) { 103 0 : error = "Unexpected result from signer"; 104 0 : return false; 105 : } 106 : 107 4 : PartiallySignedTransaction signer_psbtx; 108 4 : std::string signer_psbt_error; 109 4 : 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 4 : psbtx = signer_psbtx; 115 : 116 4 : return true; 117 4 : }