Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

backport: finish merging 25001 #6531

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
4 changes: 2 additions & 2 deletions src/base58.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ std::string EncodeBase58(Span<const unsigned char> input)

bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len)
{
if (!ValidAsCString(str)) {
if (!ContainsNoNUL(str)) {
return false;
}
return DecodeBase58(str.c_str(), vchRet, max_ret_len);
Expand Down Expand Up @@ -160,7 +160,7 @@ std::string EncodeBase58Check(Span<const unsigned char> input)

bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret)
{
if (!ValidAsCString(str)) {
if (!ContainsNoNUL(str)) {
return false;
}
return DecodeBase58Check(str.c_str(), vchRet, max_ret);
Expand Down
2 changes: 1 addition & 1 deletion src/bitcoin-tx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
template <typename T>
static T TrimAndParse(const std::string& int_str, const std::string& err)
{
const auto parsed{ToIntegral<T>(TrimString(int_str))};
const auto parsed{ToIntegral<T>(TrimStringView(int_str))};
if (!parsed.has_value()) {
throw std::runtime_error(err + " '" + int_str + "'");
}
Expand Down
9 changes: 5 additions & 4 deletions src/httprpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,11 @@ static bool RPCAuthorized(const std::string& strAuth, std::string& strAuthUserna
return false;
if (strAuth.substr(0, 6) != "Basic ")
return false;
std::string strUserPass64 = TrimString(strAuth.substr(6));
bool invalid;
std::string strUserPass = DecodeBase64(strUserPass64, &invalid);
if (invalid) return false;
std::string_view strUserPass64 = TrimStringView(std::string_view{strAuth}.substr(6));
auto userpass_data = DecodeBase64(strUserPass64);
std::string strUserPass;
if (!userpass_data) return false;
strUserPass.assign(userpass_data->begin(), userpass_data->end());

if (strUserPass.find(':') != std::string::npos)
strAuthUsernameOut = strUserPass.substr(0, strUserPass.find(':'));
Expand Down
11 changes: 5 additions & 6 deletions src/httpserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,12 +272,11 @@ static void http_request_cb(struct evhttp_request* req, void* arg)
return false;

std::string strUserPass64 = TrimString(strAuth.substr(6));
bool invalid;
std::string strUserPass = DecodeBase64(strUserPass64, &invalid);
if (invalid) return false;

if (strUserPass.find(':') == std::string::npos) return false;
const std::string username{strUserPass.substr(0, strUserPass.find(':'))};
auto opt_strUserPass = DecodeBase64(strUserPass64);
if (!opt_strUserPass.has_value()) return false;
auto it = std::find(opt_strUserPass->begin(), opt_strUserPass->end(), ':');
if (it == opt_strUserPass->end()) return false;
const std::string username = std::string(opt_strUserPass->begin(), it);
return find(g_external_usernames.begin(), g_external_usernames.end(), username) != g_external_usernames.end();
}();

Expand Down
7 changes: 3 additions & 4 deletions src/i2p.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,11 @@ static std::string SwapBase64(const std::string& from)
static Binary DecodeI2PBase64(const std::string& i2p_b64)
{
const std::string& std_b64 = SwapBase64(i2p_b64);
bool invalid;
Binary decoded = DecodeBase64(std_b64.c_str(), &invalid);
if (invalid) {
auto decoded = DecodeBase64(std_b64);
if (!decoded) {
throw std::runtime_error(strprintf("Cannot decode Base64: \"%s\"", i2p_b64));
}
return decoded;
return std::move(*decoded);
}

/**
Expand Down
22 changes: 10 additions & 12 deletions src/netaddress.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ static void Checksum(Span<const uint8_t> addr_pubkey, uint8_t (&checksum)[CHECKS

bool CNetAddr::SetSpecial(const std::string& addr)
{
if (!ValidAsCString(addr)) {
if (!ContainsNoNUL(addr)) {
return false;
}

Expand All @@ -235,17 +235,16 @@ bool CNetAddr::SetTor(const std::string& addr)
return false;
}

bool invalid;
const auto& input = DecodeBase32(addr.substr(0, addr.size() - suffix_len).c_str(), &invalid);
auto input = DecodeBase32(std::string_view{addr}.substr(0, addr.size() - suffix_len));

if (invalid) {
if (!input) {
return false;
}

if (input.size() == torv3::TOTAL_LEN) {
Span<const uint8_t> input_pubkey{input.data(), ADDR_TORV3_SIZE};
Span<const uint8_t> input_checksum{input.data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN};
Span<const uint8_t> input_version{input.data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)};
if (input->size() == torv3::TOTAL_LEN) {
Span<const uint8_t> input_pubkey{input->data(), ADDR_TORV3_SIZE};
Span<const uint8_t> input_checksum{input->data() + ADDR_TORV3_SIZE, torv3::CHECKSUM_LEN};
Span<const uint8_t> input_version{input->data() + ADDR_TORV3_SIZE + torv3::CHECKSUM_LEN, sizeof(torv3::VERSION)};

if (input_version != torv3::VERSION) {
return false;
Expand Down Expand Up @@ -281,15 +280,14 @@ bool CNetAddr::SetI2P(const std::string& addr)
// can decode it.
const std::string b32_padded = addr.substr(0, b32_len) + "====";

bool invalid;
const auto& address_bytes = DecodeBase32(b32_padded.c_str(), &invalid);
auto address_bytes = DecodeBase32(b32_padded);

if (invalid || address_bytes.size() != ADDR_I2P_SIZE) {
if (!address_bytes || address_bytes->size() != ADDR_I2P_SIZE) {
return false;
}

m_net = NET_I2P;
m_addr.assign(address_bytes.begin(), address_bytes.end());
m_addr.assign(address_bytes->begin(), address_bytes->end());

return true;
}
Expand Down
10 changes: 5 additions & 5 deletions src/netbase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ std::vector<std::string> GetNetworkNames(bool append_unroutable)

static std::vector<CNetAddr> LookupIntern(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) return {};
if (!ContainsNoNUL(name)) return {};
{
CNetAddr addr;
// From our perspective, onion addresses are not hostnames but rather
Expand Down Expand Up @@ -173,7 +173,7 @@ static std::vector<CNetAddr> LookupIntern(const std::string& name, unsigned int

std::vector<CNetAddr> LookupHost(const std::string& name, unsigned int nMaxSolutions, bool fAllowLookup, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) return {};
if (!ContainsNoNUL(name)) return {};
std::string strHost = name;
if (strHost.empty()) return {};
if (strHost.front() == '[' && strHost.back() == ']') {
Expand All @@ -191,7 +191,7 @@ std::optional<CNetAddr> LookupHost(const std::string& name, bool fAllowLookup, D

std::vector<CService> Lookup(const std::string& name, uint16_t portDefault, bool fAllowLookup, unsigned int nMaxSolutions, DNSLookupFn dns_lookup_function)
{
if (name.empty() || !ValidAsCString(name)) {
if (name.empty() || !ContainsNoNUL(name)) {
return {};
}
uint16_t port{portDefault};
Expand All @@ -216,7 +216,7 @@ std::optional<CService> Lookup(const std::string& name, uint16_t portDefault, bo

CService LookupNumeric(const std::string& name, uint16_t portDefault, DNSLookupFn dns_lookup_function)
{
if (!ValidAsCString(name)) {
if (!ContainsNoNUL(name)) {
return {};
}
// "1.2:345" will fail to resolve the ip, but will still set the port.
Expand Down Expand Up @@ -668,7 +668,7 @@ bool ConnectThroughProxy(const Proxy& proxy, const std::string& strDest, uint16_

bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out)
{
if (!ValidAsCString(subnet_str)) {
if (!ContainsNoNUL(subnet_str)) {
return false;
}

Expand Down
11 changes: 5 additions & 6 deletions src/psbt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,18 +343,17 @@ std::string PSBTRoleName(PSBTRole role) {

bool DecodeBase64PSBT(PartiallySignedTransaction& psbt, const std::string& base64_tx, std::string& error)
{
bool invalid;
std::string tx_data = DecodeBase64(base64_tx, &invalid);
if (invalid) {
auto tx_data = DecodeBase64(base64_tx);
if (!tx_data) {
error = "invalid base64";
return false;
}
return DecodeRawPSBT(psbt, tx_data, error);
return DecodeRawPSBT(psbt, MakeByteSpan(*tx_data), error);
}

bool DecodeRawPSBT(PartiallySignedTransaction& psbt, const std::string& tx_data, std::string& error)
bool DecodeRawPSBT(PartiallySignedTransaction& psbt, Span<const std::byte> tx_data, std::string& error)
{
CDataStream ss_data(MakeByteSpan(tx_data), SER_NETWORK, PROTOCOL_VERSION);
CDataStream ss_data(tx_data, SER_NETWORK, PROTOCOL_VERSION);
try {
ss_data >> psbt;
if (!ss_data.empty()) {
Expand Down
2 changes: 1 addition & 1 deletion src/psbt.h
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,6 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
//! Decode a base64ed PSBT into a PartiallySignedTransaction
[[nodiscard]] bool DecodeBase64PSBT(PartiallySignedTransaction& decoded_psbt, const std::string& base64_psbt, std::string& error);
//! Decode a raw (binary blob) PSBT into a PartiallySignedTransaction
[[nodiscard]] bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, const std::string& raw_psbt, std::string& error);
[[nodiscard]] bool DecodeRawPSBT(PartiallySignedTransaction& decoded_psbt, Span<const std::byte> raw_psbt, std::string& error);

#endif // BITCOIN_PSBT_H
12 changes: 6 additions & 6 deletions src/qt/walletframe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,16 +249,16 @@ void WalletFrame::gotoVerifyMessageTab(QString addr)

void WalletFrame::gotoLoadPSBT(bool from_clipboard)
{
std::string data;
std::vector<unsigned char> data;

if (from_clipboard) {
std::string raw = QApplication::clipboard()->text().toStdString();
bool invalid;
data = DecodeBase64(raw, &invalid);
if (invalid) {
auto result = DecodeBase64(raw);
if (!result) {
Q_EMIT message(tr("Error"), tr("Unable to decode PSBT from clipboard (invalid base64)"), CClientUIInterface::MSG_ERROR);
return;
}
data = std::move(*result);
} else {
QString filename = GUIUtil::getOpenFileName(this,
tr("Load Transaction Data"), QString(),
Expand All @@ -269,12 +269,12 @@ void WalletFrame::gotoLoadPSBT(bool from_clipboard)
return;
}
std::ifstream in{filename.toLocal8Bit().data(), std::ios::binary};
data = std::string(std::istreambuf_iterator<char>{in}, {});
data.assign(std::istream_iterator<unsigned char>{in}, {});
}

std::string error;
PartiallySignedTransaction psbtx;
if (!DecodeRawPSBT(psbtx, data, error)) {
if (!DecodeRawPSBT(psbtx, MakeByteSpan(data), error)) {
Q_EMIT message(tr("Error"), tr("Unable to decode PSBT") + "\n" + QString::fromStdString(error), CClientUIInterface::MSG_ERROR);
return;
}
Expand Down
12 changes: 6 additions & 6 deletions src/rpc/evo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -815,9 +815,9 @@ static UniValue protx_register_common_wrapper(const JSONRPCRequest& request,
} else if (err != SigningResult::OK){
throw JSONRPCError(RPC_WALLET_ERROR, SigningResultString(err));
}
bool invalid = false;
ptx.vchSig = DecodeBase64(signed_payload.c_str(), &invalid);
if (invalid) throw JSONRPCError(RPC_INTERNAL_ERROR, "failed to decode base64 ready signature for protx");
auto opt_vchSig = DecodeBase64(signed_payload);
if (!opt_vchSig.has_value()) throw JSONRPCError(RPC_INTERNAL_ERROR, "failed to decode base64 ready signature for protx");
ptx.vchSig = opt_vchSig.value();
} // cs_wallet
SetTxPayload(tx, ptx);
return SignAndSendSpecialTx(request, chain_helper, chainman, tx, fSubmit);
Expand Down Expand Up @@ -877,11 +877,11 @@ static RPCHelpMan protx_register_submit()
throw JSONRPCError(RPC_INVALID_PARAMETER, "payload signature not empty");
}

bool decode_fail{false};
ptx.vchSig = DecodeBase64(request.params[1].get_str().c_str(), &decode_fail);
if (decode_fail) {
auto opt_vchSig= DecodeBase64(request.params[1].get_str());
if (!opt_vchSig.has_value()) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "malformed base64 encoding");
}
ptx.vchSig = opt_vchSig.value();

SetTxPayload(tx, ptx);
return SignAndSendSpecialTx(request, chain_helper, chainman, tx);
Expand Down
14 changes: 6 additions & 8 deletions src/rpc/governance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -421,11 +421,10 @@ static bool SignVote(const CWallet& wallet, const CKeyID& keyID, CGovernanceVote
LogPrintf("SignVote failed due to: %s\n", SigningResultString(err));
return false;
}
bool failed = true;
const auto decoded = DecodeBase64(signature, &failed);
CHECK_NONFATAL(!failed); // DecodeBase64 should not fail
const auto opt_decoded = DecodeBase64(signature);
CHECK_NONFATAL(opt_decoded.has_value()); // DecodeBase64 should not fail

vote.SetSignature(std::vector<unsigned char>(decoded.data(), decoded.data() + decoded.size()));
vote.SetSignature(std::vector<unsigned char>(opt_decoded->data(), opt_decoded->data() + opt_decoded->size()));
return true;
}

Expand Down Expand Up @@ -959,10 +958,9 @@ static RPCHelpMan voteraw()

int64_t nTime = request.params[5].get_int64();
std::string strSig = request.params[6].get_str();
bool fInvalid = false;
std::vector<unsigned char> vchSig = DecodeBase64(strSig.c_str(), &fInvalid);
auto opt_vchSig = DecodeBase64(strSig);

if (fInvalid) {
if (!opt_vchSig.has_value()) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Malformed base64 encoding");
}

Expand All @@ -975,7 +973,7 @@ static RPCHelpMan voteraw()

CGovernanceVote vote(outpoint, hashGovObj, eVoteSignal, eVoteOutcome);
vote.SetTime(nTime);
vote.SetSignature(vchSig);
vote.SetSignature(opt_vchSig.value());

bool onlyVotingKeyAllowed = govObjType == GovernanceObject::PROPOSAL && vote.GetSignal() == VOTE_SIGNAL_FUNDING;

Expand Down
7 changes: 3 additions & 4 deletions src/stacktraces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -426,13 +426,12 @@ std::string GetCrashInfoStrFromSerializedStr(const std::string& ciStr)
{
static uint64_t basePtr = GetBaseAddress();

bool dataInvalid = false;
auto buf = DecodeBase32(ciStr.c_str(), &dataInvalid);
if (buf.empty() || dataInvalid) {
auto opt_buf = DecodeBase32(ciStr.c_str());
if (!opt_buf.has_value() || opt_buf->empty()) {
return "Error while deserializing crash info";
}

CDataStream ds(buf, SER_DISK, 0);
CDataStream ds(*opt_buf, SER_DISK, 0);

crash_info_header hdr;
try {
Expand Down
20 changes: 7 additions & 13 deletions src/test/base32_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,16 @@ BOOST_AUTO_TEST_CASE(base32_testvectors)
BOOST_CHECK_EQUAL(strEnc, vstrOut[i]);
strEnc = EncodeBase32(vstrIn[i], false);
BOOST_CHECK_EQUAL(strEnc, vstrOutNoPadding[i]);
bool invalid;
std::string strDec = DecodeBase32(vstrOut[i], &invalid);
BOOST_CHECK(!invalid);
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
auto dec = DecodeBase32(vstrOut[i]);
BOOST_REQUIRE(dec);
BOOST_CHECK_MESSAGE(MakeByteSpan(*dec) == MakeByteSpan(vstrIn[i]), vstrOut[i]);
}

// Decoding strings with embedded NUL characters should fail
bool failure;
(void)DecodeBase32("invalid\0"s, &failure); // correct size, invalid due to \0
BOOST_CHECK(failure);
(void)DecodeBase32("AWSX3VPP"s, &failure); // valid
BOOST_CHECK(!failure);
(void)DecodeBase32("AWSX3VPP\0invalid"s, &failure); // correct size, invalid due to \0
BOOST_CHECK(failure);
(void)DecodeBase32("AWSX3VPPinvalid"s, &failure); // invalid size
BOOST_CHECK(failure);
BOOST_CHECK(!DecodeBase32("invalid\0"s)); // correct size, invalid due to \0
BOOST_CHECK(DecodeBase32("AWSX3VPP"s)); // valid
BOOST_CHECK(!DecodeBase32("AWSX3VPP\0invalid"s)); // correct size, invalid due to \0
BOOST_CHECK(!DecodeBase32("AWSX3VPPinvalid"s)); // invalid size
}

BOOST_AUTO_TEST_SUITE_END()
20 changes: 7 additions & 13 deletions src/test/base64_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
{
std::string strEnc = EncodeBase64(vstrIn[i]);
BOOST_CHECK_EQUAL(strEnc, vstrOut[i]);
bool invalid;
std::string strDec = DecodeBase64(strEnc, &invalid);
BOOST_CHECK(!invalid);
BOOST_CHECK_EQUAL(strDec, vstrIn[i]);
auto dec = DecodeBase64(strEnc);
BOOST_REQUIRE(dec);
BOOST_CHECK_MESSAGE(MakeByteSpan(*dec) == MakeByteSpan(vstrIn[i]), vstrOut[i]);
}

{
Expand All @@ -36,15 +35,10 @@ BOOST_AUTO_TEST_CASE(base64_testvectors)
}

// Decoding strings with embedded NUL characters should fail
bool failure;
(void)DecodeBase64("invalid\0"s, &failure);
BOOST_CHECK(failure);
(void)DecodeBase64("nQB/pZw="s, &failure);
BOOST_CHECK(!failure);
(void)DecodeBase64("nQB/pZw=\0invalid"s, &failure);
BOOST_CHECK(failure);
(void)DecodeBase64("nQB/pZw=invalid\0"s, &failure);
BOOST_CHECK(failure);
BOOST_CHECK(!DecodeBase64("invalid\0"s));
BOOST_CHECK(DecodeBase64("nQB/pZw="s));
BOOST_CHECK(!DecodeBase64("nQB/pZw=\0invalid"s));
BOOST_CHECK(!DecodeBase64("nQB/pZw=invalid\0"s));
}

BOOST_AUTO_TEST_SUITE_END()
Loading
Loading