Skip to content

Commit 995b6c8

Browse files
committed
Merge bitcoin#17721: util: Don't allow Base58 decoding of non-Base58 strings. Add Base58 tests.
d945c6f util: Don't allow base58-decoding of std::string:s containing non-base58 characters (practicalswift) ff7a999 tests: Add tests for base58-decoding of std::string:s containing non-base58 characters (practicalswift) Pull request description: Don't allow Base58 decoding of non-Base58 strings. Add Base58 tests. Fixes bitcoin#17718. Added tests before the Base58 decoding patch: ``` $ make check … test/base58_tests.cpp(62): error: in "base58_tests/base58_DecodeBase58": check !DecodeBase58(std::string("\0invalid", 8), result) has failed test/base58_tests.cpp(67): error: in "base58_tests/base58_DecodeBase58": check !DecodeBase58(std::string("good\0bad0IOl", 12), result) has failed test/base58_tests.cpp(76): error: in "base58_tests/base58_DecodeBase58": check !DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh\00IOl", 26), result) has failed *** 3 failures are detected in the test module "Bitcoin Core Test Suite" … $ echo $? 1 ``` Added tests before the Base58 decoding patch: ``` $ make check … OK … $ echo $? 0 ``` ACKs for top commit: MarcoFalke: ACK d945c6f 🚓 laanwj: ACK d945c6f Tree-SHA512: 78fee3a18718c9cfbf2e4b26daaf8f24b4deca00475b7b254fec7f8be740f8898c696d9cd0eaa7c50bca55909b9dff3b516b6fe4db92dc132dcc0a1c5e3d61af
2 parents d4b335c + d945c6f commit 995b6c8

File tree

4 files changed

+32
-1
lines changed

4 files changed

+32
-1
lines changed

src/base58.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <hash.h>
88
#include <uint256.h>
99
#include <util/strencodings.h>
10+
#include <util/string.h>
1011

1112
#include <assert.h>
1213
#include <string.h>
@@ -130,6 +131,9 @@ std::string EncodeBase58(const std::vector<unsigned char>& vch)
130131

131132
bool DecodeBase58(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret_len)
132133
{
134+
if (!ValidAsCString(str)) {
135+
return false;
136+
}
133137
return DecodeBase58(str.c_str(), vchRet, max_ret_len);
134138
}
135139

@@ -161,5 +165,8 @@ bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int
161165

162166
bool DecodeBase58Check(const std::string& str, std::vector<unsigned char>& vchRet, int max_ret)
163167
{
168+
if (!ValidAsCString(str)) {
169+
return false;
170+
}
164171
return DecodeBase58Check(str.c_str(), vchRet, max_ret);
165172
}

src/test/base58_tests.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,24 @@ BOOST_AUTO_TEST_CASE(base58_DecodeBase58)
5959
}
6060

6161
BOOST_CHECK(!DecodeBase58("invalid", result, 100));
62+
BOOST_CHECK(!DecodeBase58(std::string("invalid"), result, 100));
63+
BOOST_CHECK(!DecodeBase58(std::string("\0invalid", 8), result, 100));
64+
65+
BOOST_CHECK(DecodeBase58(std::string("good", 4), result, 100));
66+
BOOST_CHECK(!DecodeBase58(std::string("bad0IOl", 7), result, 100));
67+
BOOST_CHECK(!DecodeBase58(std::string("goodbad0IOl", 11), result, 100));
68+
BOOST_CHECK(!DecodeBase58(std::string("good\0bad0IOl", 12), result, 100));
6269

6370
// check that DecodeBase58 skips whitespace, but still fails with unexpected non-whitespace at the end.
6471
BOOST_CHECK(!DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t a", result, 3));
6572
BOOST_CHECK( DecodeBase58(" \t\n\v\f\r skip \r\f\v\n\t ", result, 3));
6673
std::vector<unsigned char> expected = ParseHex("971a55");
6774
BOOST_CHECK_EQUAL_COLLECTIONS(result.begin(), result.end(), expected.begin(), expected.end());
75+
76+
BOOST_CHECK(DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh", 21), result, 100));
77+
BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oi", 21), result, 100));
78+
BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh0IOl", 25), result, 100));
79+
BOOST_CHECK(!DecodeBase58Check(std::string("3vQB7B6MrGQZaxCuFg4oh\00IOl", 26), result, 100));
6880
}
6981

7082
BOOST_AUTO_TEST_CASE(base58_random_encode_decode)

src/util/strencodings.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

66
#include <util/strencodings.h>
7+
#include <util/string.h>
78

89
#include <tinyformat.h>
910

@@ -269,7 +270,7 @@ NODISCARD static bool ParsePrechecks(const std::string& str)
269270
return false;
270271
if (str.size() >= 1 && (IsSpace(str[0]) || IsSpace(str[str.size()-1]))) // No padding allowed
271272
return false;
272-
if (str.size() != strlen(str.c_str())) // No embedded NUL characters allowed
273+
if (!ValidAsCString(str)) // No embedded NUL characters allowed
273274
return false;
274275
return true;
275276
}

src/util/string.h

+11
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#ifndef BITCOIN_UTIL_STRING_H
66
#define BITCOIN_UTIL_STRING_H
77

8+
#include <attributes.h>
9+
10+
#include <cstring>
811
#include <string>
912
#include <vector>
1013

@@ -31,4 +34,12 @@ inline std::string Join(const std::vector<std::string>& list, const std::string&
3134
return Join(list, separator, [](const std::string& i) { return i; });
3235
}
3336

37+
/**
38+
* Check if a string does not contain any embedded NUL (\0) characters
39+
*/
40+
NODISCARD inline bool ValidAsCString(const std::string& str) noexcept
41+
{
42+
return str.size() == strlen(str.c_str());
43+
}
44+
3445
#endif // BITCOIN_UTIL_STRENCODINGS_H

0 commit comments

Comments
 (0)