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

Base58 decoding is done without checking that the input size is reasonable #17501

Closed
practicalswift opened this issue Nov 17, 2019 · 3 comments · Fixed by #17511
Closed

Base58 decoding is done without checking that the input size is reasonable #17501

practicalswift opened this issue Nov 17, 2019 · 3 comments · Fixed by #17511

Comments

@practicalswift
Copy link
Contributor

Base58 decoding is currently done without checking that the input size is reasonable.

This can lead to excessive decoding run time if an attacker can control the base58 input being decoded.

DecodeBase58/DecodeBase58Check(…) run time sampled with varying input sizes:

  • 1 000 bytes: 1 ms
  • 10 000 bytes: 97 ms
  • 100 000 bytes: 8 865 ms (9 seconds)
  • 1 000 000 bytes: 857 440 ms (14 minutes)
  • 10 000 000 bytes: too long :)

DecodeBase58/DecodeBase58Check(…) is reachable via the RPC interface using the following code paths:

addmultisigaddress(JSONRPCRequest const&) → AddrToPubKey(CKeyStore*, std::string const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
createpsbt(JSONRPCRequest const&) → ConstructTransaction(UniValue const&, UniValue const&, UniValue const&, UniValue const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
createrawtransaction(JSONRPCRequest const&) → ConstructTransaction(UniValue const&, UniValue const&, UniValue const&, UniValue const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
createwallet(JSONRPCRequest const&) → CWallet::CreateWalletFromFile(interfaces::Chain&, WalletLocation const&, unsigned long) → CWallet::LoadWallet(bool&) → WalletBatch::LoadWallet(CWallet*) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
deriveaddresses(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
deriveaddresses(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtPubKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
deriveaddresses(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
deriveaddresses(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
dumpprivkey(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
fundrawtransaction(JSONRPCRequest const&) → FundTransaction(CWallet*, CMutableTransaction&, long&, int&, UniValue) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
generatetoaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getaddressinfo(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getdescriptorinfo(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getdescriptorinfo(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtPubKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getdescriptorinfo(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getdescriptorinfo(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
getreceivedbyaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtPubKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → ProcessImportLegacy(ImportData&, std::map<CKeyID, CPubKey, std::less<CKeyID>, std::allocator<std::pair<CKeyID const, CPubKey> > >&, std::map<CKeyID, CKey, std::less<CKeyID>, std::allocator<std::pair<CKeyID const, CKey> > >&, std::set<CScript, std::less<CScript>, std::allocator<CScript> >&, bool&, UniValue const&, std::vector<CKeyID>&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importmulti(JSONRPCRequest const&) → ProcessImportLegacy(ImportData&, std::map<CKeyID, CPubKey, std::less<CKeyID>, std::allocator<std::pair<CKeyID const, CPubKey> > >&, std::map<CKeyID, CKey, std::less<CKeyID>, std::allocator<std::pair<CKeyID const, CKey> > >&, std::set<CScript, std::less<CScript>, std::allocator<CScript> >&, bool&, UniValue const&, std::vector<CKeyID>&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importprivkey(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
importwallet(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
listreceivedbyaddress(JSONRPCRequest const&) → ListReceived(interfaces::Chain::Lock&, CWallet*, UniValue const&, bool) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
listreceivedbylabel(JSONRPCRequest const&) → ListReceived(interfaces::Chain::Lock&, CWallet*, UniValue const&, bool) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
listunspent(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
loadwallet(JSONRPCRequest const&) → LoadWallet(interfaces::Chain&, WalletLocation const&, std::string&, std::string&) → CWallet::CreateWalletFromFile(interfaces::Chain&, WalletLocation const&, unsigned long) → CWallet::LoadWallet(bool&) → WalletBatch::LoadWallet(CWallet*) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
scantxoutset(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
scantxoutset(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeExtPubKey(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
scantxoutset(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → (anonymous namespace)::ParsePubkey(Span<char const> const&, bool, FlatSigningProvider&) → (anonymous namespace)::ParsePubkeyInner(Span<char const> const&, bool, FlatSigningProvider&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
scantxoutset(JSONRPCRequest const&) → Parse(std::string const&, FlatSigningProvider&, bool) → (anonymous namespace)::ParseScript(Span<char const>&, (anonymous namespace)::ParseScriptContext, FlatSigningProvider&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
sendmany(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
sendtoaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
sethdseed(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
setlabel(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
signmessage(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
signmessagewithprivkey(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
signrawtransactionwithkey(JSONRPCRequest const&) → DecodeSecret(std::string const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
validateaddress(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
verifymessage(JSONRPCRequest const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
walletcreatefundedpsbt(JSONRPCRequest const&) → ConstructTransaction(UniValue const&, UniValue const&, UniValue const&, UniValue const&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
walletcreatefundedpsbt(JSONRPCRequest const&) → FundTransaction(CWallet*, CMutableTransaction&, long&, int&, UniValue) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)

Other code paths involving base58-decoding:

IsValidDestinationString(std::string const&, CChainParams const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
LoadWallet(interfaces::Chain&, std::string const&, std::string&, std::string&) → LoadWallet(interfaces::Chain&, WalletLocation const&, std::string&, std::string&) → CWallet::CreateWalletFromFile(interfaces::Chain&, WalletLocation const&, unsigned long) → CWallet::LoadWallet(bool&) → WalletBatch::LoadWallet(CWallet*) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
LoadWallets(interfaces::Chain&, std::vector<std::string, std::allocator<std::string > > const&) → CWallet::CreateWalletFromFile(interfaces::Chain&, WalletLocation const&, unsigned long) → CWallet::LoadWallet(bool&) → WalletBatch::LoadWallet(CWallet*) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
WalletBatch::RecoverKeysOnlyFilter(void*, CDataStream, CDataStream) → ReadKeyValue(CWallet*, CDataStream&, CDataStream&, CWalletScanState&, std::string&, std::string&) → DecodeDestination(std::string const&) → (anonymous namespace)::DecodeDestination(std::string const&, CChainParams const&) → DecodeBase58Check(std::string const&, std::vector<unsigned char>&)
@laanwj
Copy link
Member

laanwj commented Nov 18, 2019

I would say it's not the encoder/decoder responsibility to check input sizes. Good generic code works for any input size.

But of course, the application side (e.g. address parsing routines) could have a check to see if inputs are reasonable. They have that knowledge.

@practicalswift
Copy link
Contributor Author

practicalswift commented Nov 18, 2019

@laanwj Yes, that information would need to be either a.) provided by the caller for enforcement in DecodeBase58, or b.) enforced by the caller itself. As you say DecodeBase58 as it works today has no concept of "reasonable size" obviously :)

Also the documentation of DecodeBase58 should probably be updated to reflect this obligation of the caller.

@laanwj
Copy link
Member

laanwj commented Nov 18, 2019

In any case, I think the surprising thing here, for most users of strings encodings such as Base64, is that decode time doesn't scale linearly with size. It would make sense to document that.
(this is because it's implemented with bigint arithmetic, and bigint arithmetic is not linear time in operations)

@laanwj laanwj closed this as completed in 3914e87 Dec 12, 2019
sidhujag pushed a commit to syscoin/syscoin that referenced this issue Dec 12, 2019
5909bcd Add bounds checks in key_io before DecodeBase58Check (Pieter Wuille)
2bcf1fc Pass a maximum output length to DecodeBase58 and DecodeBase58Check (Pieter Wuille)

Pull request description:

  Fixes bitcoin#17501.

ACKs for top commit:
  laanwj:
    code review ACK 5909bcd
  practicalswift:
    ACK 5909bcd -- code looks correct

Tree-SHA512: 4807f4a9508dee9c0f1ad63f56f70f4ec4e6b7e35eb91322a525e3da3828521a41de9b8338a6bf67250803660b480d95fd02ce6b2fe79c4c88bc19b54f9d8889
sidhujag pushed a commit to syscoin-core/syscoin that referenced this issue Nov 10, 2020
5909bcd Add bounds checks in key_io before DecodeBase58Check (Pieter Wuille)
2bcf1fc Pass a maximum output length to DecodeBase58 and DecodeBase58Check (Pieter Wuille)

Pull request description:

  Fixes bitcoin#17501.

ACKs for top commit:
  laanwj:
    code review ACK 5909bcd
  practicalswift:
    ACK 5909bcd -- code looks correct

Tree-SHA512: 4807f4a9508dee9c0f1ad63f56f70f4ec4e6b7e35eb91322a525e3da3828521a41de9b8338a6bf67250803660b480d95fd02ce6b2fe79c4c88bc19b54f9d8889
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Dec 16, 2021
knst pushed a commit to knst/dash that referenced this issue Jun 7, 2022
5909bcd Add bounds checks in key_io before DecodeBase58Check (Pieter Wuille)
2bcf1fc Pass a maximum output length to DecodeBase58 and DecodeBase58Check (Pieter Wuille)

Pull request description:

  Fixes bitcoin#17501.

ACKs for top commit:
  laanwj:
    code review ACK 5909bcd
  practicalswift:
    ACK 5909bcd -- code looks correct

Tree-SHA512: 4807f4a9508dee9c0f1ad63f56f70f4ec4e6b7e35eb91322a525e3da3828521a41de9b8338a6bf67250803660b480d95fd02ce6b2fe79c4c88bc19b54f9d8889
knst pushed a commit to knst/dash that referenced this issue Jun 8, 2022
5909bcd Add bounds checks in key_io before DecodeBase58Check (Pieter Wuille)
2bcf1fc Pass a maximum output length to DecodeBase58 and DecodeBase58Check (Pieter Wuille)

Pull request description:

  Fixes bitcoin#17501.

ACKs for top commit:
  laanwj:
    code review ACK 5909bcd
  practicalswift:
    ACK 5909bcd -- code looks correct

Tree-SHA512: 4807f4a9508dee9c0f1ad63f56f70f4ec4e6b7e35eb91322a525e3da3828521a41de9b8338a6bf67250803660b480d95fd02ce6b2fe79c4c88bc19b54f9d8889
gades pushed a commit to cosanta/cosanta-core that referenced this issue Dec 3, 2023
5909bcd Add bounds checks in key_io before DecodeBase58Check (Pieter Wuille)
2bcf1fc Pass a maximum output length to DecodeBase58 and DecodeBase58Check (Pieter Wuille)

Pull request description:

  Fixes bitcoin#17501.

ACKs for top commit:
  laanwj:
    code review ACK 5909bcd
  practicalswift:
    ACK 5909bcd -- code looks correct

Tree-SHA512: 4807f4a9508dee9c0f1ad63f56f70f4ec4e6b7e35eb91322a525e3da3828521a41de9b8338a6bf67250803660b480d95fd02ce6b2fe79c4c88bc19b54f9d8889
gades pushed a commit to piratecash/pirate that referenced this issue Dec 10, 2023
5909bcd Add bounds checks in key_io before DecodeBase58Check (Pieter Wuille)
2bcf1fc Pass a maximum output length to DecodeBase58 and DecodeBase58Check (Pieter Wuille)

Pull request description:

  Fixes bitcoin#17501.

ACKs for top commit:
  laanwj:
    code review ACK 5909bcd
  practicalswift:
    ACK 5909bcd -- code looks correct

Tree-SHA512: 4807f4a9508dee9c0f1ad63f56f70f4ec4e6b7e35eb91322a525e3da3828521a41de9b8338a6bf67250803660b480d95fd02ce6b2fe79c4c88bc19b54f9d8889
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants