Add checks in cryptonote serialization routine

This commit is contained in:
Lee *!* Clagett
2026-08-30 17:32:53 -04:00
parent 78fb311ebb
commit 2fe7534434
4 changed files with 45 additions and 23 deletions
+2 -2
View File
@@ -258,7 +258,7 @@ namespace cryptonote
ar.tag("signatures"); ar.tag("signatures");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures); PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures, 0);
bool signatures_not_expected = signatures.empty(); bool signatures_not_expected = signatures.empty();
if (!signatures_not_expected && vin.size() != signatures.size()) if (!signatures_not_expected && vin.size() != signatures.size())
return false; return false;
@@ -274,7 +274,7 @@ namespace cryptonote
return false; return false;
} }
PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]); PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i], sizeof(crypto::signature));
if (signature_size != signatures[i].size()) if (signature_size != signatures[i].size())
return false; return false;
+25 -13
View File
@@ -346,7 +346,7 @@ namespace rct {
{ {
ar.tag("pseudoOuts"); ar.tag("pseudoOuts");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts); PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts, sizeof(key));
if (pseudoOuts.size() != inputs) if (pseudoOuts.size() != inputs)
return false; return false;
for (size_t i = 0; i < inputs; ++i) for (size_t i = 0; i < inputs; ++i)
@@ -360,12 +360,18 @@ namespace rct {
ar.tag("ecdhInfo"); ar.tag("ecdhInfo");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, ecdhInfo);
const bool compressed_ecdh =
(type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus);
const std::size_t min_size = compressed_ecdh ? sizeof(crypto::hash8) : sizeof(key) * 2;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, ecdhInfo, min_size);
if (ecdhInfo.size() != outputs) if (ecdhInfo.size() != outputs)
return false; return false;
for (size_t i = 0; i < outputs; ++i) for (size_t i = 0; i < outputs; ++i)
{ {
if (type == RCTTypeBulletproof2 || type == RCTTypeCLSAG || type == RCTTypeBulletproofPlus) if (compressed_ecdh)
{ {
// Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the // Since RCTTypeBulletproof2 enote types, we don't serialize the blinding factor, and only serialize the
// first 8 bytes of ecdhInfo[i].amount // first 8 bytes of ecdhInfo[i].amount
@@ -391,7 +397,7 @@ namespace rct {
ar.tag("outPk"); ar.tag("outPk");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk); PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, outPk, sizeof(key));
if (outPk.size() != outputs) if (outPk.size() != outputs)
return false; return false;
for (size_t i = 0; i < outputs; ++i) for (size_t i = 0; i < outputs; ++i)
@@ -444,7 +450,7 @@ namespace rct {
ar.begin_array(); ar.begin_array();
if (nbp > outputs) if (nbp > outputs)
return false; return false;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs_plus); PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs_plus, sizeof(key) * 6);
for (size_t i = 0; i < nbp; ++i) for (size_t i = 0; i < nbp; ++i)
{ {
FIELDS(bulletproofs_plus[i]) FIELDS(bulletproofs_plus[i])
@@ -466,7 +472,7 @@ namespace rct {
ar.begin_array(); ar.begin_array();
if (nbp > outputs) if (nbp > outputs)
return false; return false;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs); PREPARE_CUSTOM_VECTOR_SERIALIZATION(nbp, bulletproofs, sizeof(key) * 9);
for (size_t i = 0; i < nbp; ++i) for (size_t i = 0; i < nbp; ++i)
{ {
FIELDS(bulletproofs[i]) FIELDS(bulletproofs[i])
@@ -481,7 +487,7 @@ namespace rct {
{ {
ar.tag("rangeSigs"); ar.tag("rangeSigs");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs); PREPARE_CUSTOM_VECTOR_SERIALIZATION(outputs, rangeSigs, sizeof(key) * 193);
if (rangeSigs.size() != outputs) if (rangeSigs.size() != outputs)
return false; return false;
for (size_t i = 0; i < outputs; ++i) for (size_t i = 0; i < outputs; ++i)
@@ -497,7 +503,7 @@ namespace rct {
{ {
ar.tag("CLSAGs"); ar.tag("CLSAGs");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, CLSAGs); PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, CLSAGs, sizeof(key) * 3);
if (CLSAGs.size() != inputs) if (CLSAGs.size() != inputs)
return false; return false;
for (size_t i = 0; i < inputs; ++i) for (size_t i = 0; i < inputs; ++i)
@@ -508,7 +514,7 @@ namespace rct {
ar.begin_object(); ar.begin_object();
ar.tag("s"); ar.tag("s");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, CLSAGs[i].s); PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, CLSAGs[i].s, sizeof(key));
if (CLSAGs[i].s.size() != mixin + 1) if (CLSAGs[i].s.size() != mixin + 1)
return false; return false;
for (size_t j = 0; j <= mixin; ++j) for (size_t j = 0; j <= mixin; ++j)
@@ -540,9 +546,12 @@ namespace rct {
// we keep a byte for size of MGs, because we don't know whether this is // we keep a byte for size of MGs, because we don't know whether this is
// a simple or full rct signature, and it's starting to annoy the hell out of me // a simple or full rct signature, and it's starting to annoy the hell out of me
size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? inputs : 1; size_t mg_elements = (type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? inputs : 1;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs);
// Each MGs has `cc` (`key`) AND at least 1 MGs[i].ss which has at least 1 `key`
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_elements, MGs, sizeof(key) * 2);
if (MGs.size() != mg_elements) if (MGs.size() != mg_elements)
return false; return false;
for (size_t i = 0; i < mg_elements; ++i) for (size_t i = 0; i < mg_elements; ++i)
{ {
// we save the MGs contents directly, because we want it to save its // we save the MGs contents directly, because we want it to save its
@@ -551,14 +560,17 @@ namespace rct {
ar.begin_object(); ar.begin_object();
ar.tag("ss"); ar.tag("ss");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1, MGs[i].ss);
// each MGs[i].ss has at least one `key`
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mixin + 1,MGs[i].ss, sizeof(key));
if (MGs[i].ss.size() != mixin + 1) if (MGs[i].ss.size() != mixin + 1)
return false; return false;
for (size_t j = 0; j < mixin + 1; ++j) for (size_t j = 0; j < mixin + 1; ++j)
{ {
ar.begin_array(); ar.begin_array();
size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? 1 : inputs) + 1; size_t mg_ss2_elements = ((type == RCTTypeSimple || type == RCTTypeBulletproof || type == RCTTypeBulletproof2) ? 1 : inputs) + 1;
PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j]); PREPARE_CUSTOM_VECTOR_SERIALIZATION(mg_ss2_elements, MGs[i].ss[j], sizeof(key));
if (MGs[i].ss[j].size() != mg_ss2_elements) if (MGs[i].ss[j].size() != mg_ss2_elements)
return false; return false;
for (size_t k = 0; k < mg_ss2_elements; ++k) for (size_t k = 0; k < mg_ss2_elements; ++k)
@@ -588,7 +600,7 @@ namespace rct {
{ {
ar.tag("pseudoOuts"); ar.tag("pseudoOuts");
ar.begin_array(); ar.begin_array();
PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts); PREPARE_CUSTOM_VECTOR_SERIALIZATION(inputs, pseudoOuts, sizeof(key));
if (pseudoOuts.size() != inputs) if (pseudoOuts.size() != inputs)
return false; return false;
for (size_t i = 0; i < inputs; ++i) for (size_t i = 0; i < inputs; ++i)
+1 -1
View File
@@ -46,7 +46,7 @@ bool do_serialize(Archive<false> &ar, std::vector<crypto::signature> &v)
v.clear(); v.clear();
// very basic sanity check // very basic sanity check
if (ar.remaining_bytes() < cnt*sizeof(crypto::signature)) { if (ar.remaining_bytes() / sizeof(crypto::signature) < cnt) {
ar.set_fail(); ar.set_fail();
return false; return false;
} }
+17 -7
View File
@@ -195,10 +195,15 @@ inline auto do_serialize(Archive &ar, T &v, Args&&... args)
template <bool W, template <bool> class Archive> \ template <bool W, template <bool> class Archive> \
bool do_serialize_object(Archive<W> &ar, stype &v) { bool do_serialize_object(Archive<W> &ar, stype &v) {
/*! \macro PREPARE_CUSTOM_VECTOR_SERIALIZATION /*! \macro RESERVE_VECTOR_SERIALIZATION. `min_wire` must be the minimum bytes
* each element takes on the wire.
*/ */
#define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec) \ #define PREPARE_CUSTOM_VECTOR_SERIALIZATION(size, vec, min_wire) \
::serialization::detail::prepare_custom_vector_serialization(size, vec, typename Archive<W>::is_saving()) do \
{ \
if (!::serialization::detail::prepare_custom_vector_serialization(size, vec, min_wire, ar)) \
return false; \
} while (0);
/*! \macro END_SERIALIZE /*! \macro END_SERIALIZE
* \brief self-explanatory * \brief self-explanatory
@@ -295,6 +300,7 @@ inline auto do_serialize(Archive &ar, T &v, Args&&... args)
namespace serialization { namespace serialization {
/*! \namespace detail /*! \namespace detail
* *
* \brief declaration and default definition for the functions used the API * \brief declaration and default definition for the functions used the API
@@ -306,15 +312,19 @@ namespace serialization {
* *
* prepares the vector /vec for serialization * prepares the vector /vec for serialization
*/ */
template <typename T> template <typename T, template<bool> class A>
void prepare_custom_vector_serialization(size_t size, std::vector<T>& vec, const boost::mpl::bool_<true>& /*is_saving*/) constexpr bool prepare_custom_vector_serialization(size_t, const std::vector<T>& vec, size_t, const A<true>&) noexcept
{ {
return true;
} }
template <typename T> template <typename T, template<bool> class A>
void prepare_custom_vector_serialization(size_t size, std::vector<T>& vec, const boost::mpl::bool_<false>& /*is_saving*/) bool prepare_custom_vector_serialization(const size_t size, std::vector<T>& vec, const size_t min_size, const A<false>& ar)
{ {
if (size && ar.remaining_bytes() / size < min_size)
return false;
vec.resize(size); vec.resize(size);
return true;
} }
/*! \fn do_check_stream_state /*! \fn do_check_stream_state