Skip to content

Commit c9d1040

Browse files
author
MarcoFalke
committed
Merge #19237: wallet: Check size after unserializing a pubkey
37ae687 Add tests for CPubKey serialization/unserialization (Elichai Turkel) 9b8907f Check size after Unserializing CPubKey (Elichai Turkel) Pull request description: Found by practicalswift, closes #19235 Currently all the public API(except the pointer-like API) in CPubKey that sets/constructs a pubkey goes through `CPubKey::Set` which checks if that the length and size match and if not invalidates the key. This adds the same check to `CPubKey::Unserialize`, sadly I don't see an easy way to just push this to the existing checks in `CPubKey::Set` but it's only a simple condition. The problem with not invalidating is that if you write a pubkey like: `{0x02,0x00}` it will think the actual length is 33(because of `size()`) and will access uninitialized memory if you call any of the functions on CPubKey. ACKs for top commit: practicalswift: re-ACK 37ae687 jonatack: Code review re-ACK 37ae687 per `git diff eab8ee3 37ae687` only change since last review at eab8ee3 is passing the `pubkey` param by reference to const instead of by value in `src/test/key_tests.cpp::CmpSerializationPubkey` MarcoFalke: ACK 37ae687 Tree-SHA512: 30173755555dfc76d6263fb6a59f41be36049ffae7b4e1b92b922d668f5e5e2331f7374d5fa10d5d59fc53020d2966156905ffcfa8b8129c1f6d0ca062174ff1
2 parents 67881de + 37ae687 commit c9d1040

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/pubkey.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ class CPubKey
142142
unsigned int len = ::ReadCompactSize(s);
143143
if (len <= SIZE) {
144144
s.read((char*)vch, len);
145+
if (len != size()) {
146+
Invalidate();
147+
}
145148
} else {
146149
// invalid pubkey, skip available data
147150
char dummy;

src/test/key_tests.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <key.h>
66

77
#include <key_io.h>
8+
#include <streams.h>
89
#include <test/util/setup_common.h>
910
#include <uint256.h>
1011
#include <util/strencodings.h>
@@ -220,4 +221,47 @@ BOOST_AUTO_TEST_CASE(key_key_negation)
220221
BOOST_CHECK(key.GetPubKey().data()[0] == 0x03);
221222
}
222223

224+
static CPubKey UnserializePubkey(const std::vector<uint8_t>& data)
225+
{
226+
CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
227+
stream << data;
228+
CPubKey pubkey;
229+
stream >> pubkey;
230+
return pubkey;
231+
}
232+
233+
static unsigned int GetLen(unsigned char chHeader)
234+
{
235+
if (chHeader == 2 || chHeader == 3)
236+
return CPubKey::COMPRESSED_SIZE;
237+
if (chHeader == 4 || chHeader == 6 || chHeader == 7)
238+
return CPubKey::SIZE;
239+
return 0;
240+
}
241+
242+
static void CmpSerializationPubkey(const CPubKey& pubkey)
243+
{
244+
CDataStream stream{SER_NETWORK, INIT_PROTO_VERSION};
245+
stream << pubkey;
246+
CPubKey pubkey2;
247+
stream >> pubkey2;
248+
BOOST_CHECK(pubkey == pubkey2);
249+
}
250+
251+
BOOST_AUTO_TEST_CASE(pubkey_unserialize)
252+
{
253+
for (uint8_t i = 2; i <= 7; ++i) {
254+
CPubKey key = UnserializePubkey({0x02});
255+
BOOST_CHECK(!key.IsValid());
256+
CmpSerializationPubkey(key);
257+
key = UnserializePubkey(std::vector<uint8_t>(GetLen(i), i));
258+
CmpSerializationPubkey(key);
259+
if (i == 5) {
260+
BOOST_CHECK(!key.IsValid());
261+
} else {
262+
BOOST_CHECK(key.IsValid());
263+
}
264+
}
265+
}
266+
223267
BOOST_AUTO_TEST_SUITE_END()

0 commit comments

Comments
 (0)