Clean up and modernize code:

This commit removes obsolete comments, dead or no longer useful
code, and workarounds for several issues that were present in older
compilers that we no longer support.

Specifically:

- It improves the transaction metadata handling class, simplifying
  its use and making it less error-prone.
- It reduces the footprint of the Serializer class by consolidating
  code and leveraging templates.
- It cleanups the ST* class hierarchy, removing dead code, improving
  and consolidating code to reduce complexity and code duplication.
- It shores up the handling of currency codes and the conversation
  between 160-bit currency codes and their string representation.
- It migrates beast::secure_erase to the ripple namespace and uses
  a call to OpenSSL_cleanse instead of the custom implementation.
This commit is contained in:
Nik Bougalis
2020-03-27 14:26:46 -07:00
parent 6c72d5cf7e
commit dbee3f01b7
45 changed files with 244 additions and 703 deletions

View File

@@ -34,7 +34,7 @@ serializePayChanAuthorization(
XRPAmount const& amt)
{
msg.add32(HashPrefix::paymentChannelClaim);
msg.add256(key);
msg.addBitString(key);
msg.add64(amt.drops());
}

View File

@@ -30,14 +30,9 @@ class STArray final : public STBase, public CountedObject<STArray>
private:
using list_type = std::vector<STObject>;
enum { reserveSize = 8 };
list_type v_;
public:
// Read-only iteration
class Items;
static char const*
getCountedObjectName()
{
@@ -48,7 +43,7 @@ public:
using iterator = list_type::iterator;
using const_iterator = list_type::const_iterator;
STArray();
STArray() = default;
STArray(STArray&&);
STArray(STArray const&) = default;
STArray(SField const& f, int n);

View File

@@ -239,8 +239,6 @@ private:
}
};
enum { reserveSize = 20 };
using list_type = std::vector<detail::STVar>;
list_type v_;
@@ -281,7 +279,7 @@ public:
explicit STObject(SField const& name);
virtual ~STObject();
virtual ~STObject() = default;
STBase*
copy(std::size_t n, void* buf) const override

View File

@@ -26,20 +26,16 @@
#include <ripple/basics/base_uint.h>
#include <ripple/basics/contract.h>
#include <ripple/basics/safe_cast.h>
#include <ripple/beast/crypto/secure_erase.h>
#include <ripple/protocol/HashPrefix.h>
#include <ripple/protocol/SField.h>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iomanip>
#include <sstream>
#include <type_traits>
namespace ripple {
class CKey; // forward declaration
class Serializer
{
private:
@@ -83,34 +79,24 @@ public:
// assemble functions
int
add8(unsigned char byte);
int add16(std::uint16_t);
int add32(std::uint32_t); // ledger indexes, account sequence, timestamps
int add32(HashPrefix);
int add64(std::uint64_t); // native currency amounts
add8(unsigned char i);
int
add128(const uint128&); // private key generators
add16(std::uint16_t i);
int
add256(uint256 const&); // transaction and ledger hashes
add32(std::uint32_t i); // ledger indexes, account sequence, timestamps
int
add32(HashPrefix p);
int
add64(std::uint64_t i); // native currency amounts
template <typename Integer>
int addInteger(Integer);
template <int Bits, class Tag>
template <std::size_t Bits, class Tag>
int
addBitString(base_uint<Bits, Tag> const& v)
{
int ret = mData.size();
mData.insert(mData.end(), v.begin(), v.end());
return ret;
}
// TODO(tom): merge with add128 and add256.
template <class Tag>
int
add160(base_uint<160, Tag> const& i)
{
return addBitString<160, Tag>(i);
return addRaw(v.data(), v.size());
}
int
@@ -119,8 +105,6 @@ public:
addRaw(const void* ptr, int len);
int
addRaw(const Serializer& s);
int
addZeros(size_t uBytes);
int
addVL(Blob const& vector);
@@ -135,8 +119,6 @@ public:
// disassemble functions
bool
get8(int&, int offset) const;
bool
get256(uint256&, int offset) const;
template <typename Integer>
bool
@@ -157,7 +139,7 @@ public:
return true;
}
template <int Bits, typename Tag = void>
template <std::size_t Bits, typename Tag = void>
bool
getBitString(base_uint<Bits, Tag>& data, int offset) const
{
@@ -167,24 +149,6 @@ public:
return success;
}
// TODO(tom): merge with get128 and get256.
template <class Tag>
bool
get160(base_uint<160, Tag>& o, int offset) const
{
return getBitString<160, Tag>(o, offset);
}
bool
getRaw(Blob&, int offset, int length) const;
Blob
getRaw(int offset, int length) const;
bool
getVL(Blob& objectVL, int offset, int& length) const;
bool
getVLLength(int& length, int offset) const;
int
addFieldID(int type, int name);
int
@@ -240,12 +204,6 @@ public:
return std::string(static_cast<const char*>(getDataPtr()), size());
}
void
secureErase()
{
beast::secure_erase(mData.data(), mData.size());
mData.clear();
}
void
erase()
{
mData.clear();
@@ -311,19 +269,6 @@ public:
return v.mData != mData;
}
std::string
getHex() const
{
std::stringstream h;
for (unsigned char const& element : mData)
{
h << std::setw(2) << std::hex << std::setfill('0')
<< safe_cast<unsigned int>(element);
}
return h.str();
}
static int
decodeLengthLength(int b1);
static int
@@ -334,11 +279,6 @@ public:
decodeVLLength(int b1, int b2, int b3);
private:
static int
lengthVL(int length)
{
return length + encodeLengthLength(length);
}
static int
encodeLengthLength(int length); // length to encode length
int
@@ -414,7 +354,7 @@ public:
std::uint64_t
get64();
template <int Bits, class Tag = void>
template <std::size_t Bits, class Tag = void>
base_uint<Bits, Tag>
getBitString();
@@ -467,7 +407,7 @@ public:
getRawHelper(int size);
};
template <int Bits, class Tag>
template <std::size_t Bits, class Tag>
base_uint<Bits, Tag>
SerialIter::getBitString()
{

View File

@@ -84,7 +84,7 @@ startMultiSigningData(STObject const& obj);
inline void
finishMultiSigningData(AccountID const& signingID, Serializer& s)
{
s.add160(signingID);
s.addBitString(signingID);
}
} // namespace ripple

View File

@@ -81,11 +81,22 @@ isXRP(Currency const& c)
std::string
to_string(Currency const& c);
/** Tries to convert a string to a Currency, returns true on success. */
/** Tries to convert a string to a Currency, returns true on success.
@note This function will return success if the resulting currency is
badCurrency(). This legacy behavior is unfortunate; changing this
will require very careful checking everywhere and may mean having
to rewrite some unit test code.
*/
bool
to_currency(Currency&, std::string const&);
/** Tries to convert a string to a Currency, returns noCurrency() on failure. */
/** Tries to convert a string to a Currency, returns noCurrency() on failure.
@note This function can return badCurrency(). This legacy behavior is
unfortunate; changing this will require very careful checking
everywhere and may mean having to rewrite some unit test code.
*/
Currency
to_currency(std::string const&);

View File

@@ -208,7 +208,7 @@ private:
inline void erase(std::true_type)
{
beast::secure_erase(&h_, sizeof(h_));
secure_erase(&h_, sizeof(h_));
}
};
@@ -221,16 +221,6 @@ using sha512_half_hasher_s = detail::basic_sha512_half_hasher<true>;
//------------------------------------------------------------------------------
#ifdef _MSC_VER
// Call from main to fix magic statics pre-VS2015
inline void
sha512_deprecatedMSVCWorkaround()
{
beast::sha512_hasher h;
auto const digest = static_cast<beast::sha512_hasher::result_type>(h);
}
#endif
/** Returns the SHA512-Half of a series of objects. */
template <class... Args>
sha512_half_hasher::result_type

View File

@@ -624,8 +624,8 @@ STAmount::add(Serializer& s) const
(static_cast<std::uint64_t>(mOffset + 512 + 256 + 97)
<< (64 - 10)));
s.add160(mIssue.currency);
s.add160(mIssue.account);
s.addBitString(mIssue.currency);
s.addBitString(mIssue.account);
}
}

View File

@@ -24,14 +24,6 @@
namespace ripple {
STArray::STArray()
{
// VFALCO NOTE We need to determine if this is
// the right thing to do, and consider
// making it optional.
// v_.reserve(reserveSize);
}
STArray::STArray(STArray&& other)
: STBase(other.getFName()), v_(std::move(other.v_))
{
@@ -52,7 +44,6 @@ STArray::STArray(int n)
STArray::STArray(SField const& f) : STBase(f)
{
v_.reserve(reserveSize);
}
STArray::STArray(SField const& f, int n) : STBase(f)

View File

@@ -26,15 +26,6 @@
namespace ripple {
STObject::~STObject()
{
#if 0
// Turn this on to get a histogram on exit
static Log log;
log(v_.size());
#endif
}
STObject::STObject(STObject&& other)
: STBase(other.getFName()), v_(std::move(other.v_)), mType(other.mType)
{
@@ -42,8 +33,6 @@ STObject::STObject(STObject&& other)
STObject::STObject(SField const& name) : STBase(name), mType(nullptr)
{
// VFALCO TODO See if this is the right thing to do
// v_.reserve(reserveSize);
}
STObject::STObject(SOTemplate const& type, SField const& name) : STBase(name)

View File

@@ -202,13 +202,13 @@ STPathSet::add(Serializer& s) const
s.add8(iType);
if (iType & STPathElement::typeAccount)
s.add160(speElement.getAccountID());
s.addBitString(speElement.getAccountID());
if (iType & STPathElement::typeCurrency)
s.add160(speElement.getCurrency());
s.addBitString(speElement.getCurrency());
if (iType & STPathElement::typeIssuer)
s.add160(speElement.getIssuerID());
s.addBitString(speElement.getIssuerID());
}
first = false;

View File

@@ -19,10 +19,10 @@
#include <ripple/basics/contract.h>
#include <ripple/basics/strHex.h>
#include <ripple/beast/crypto/secure_erase.h>
#include <ripple/beast/utility/rngfill.h>
#include <ripple/crypto/GenerateDeterministicKey.h>
#include <ripple/crypto/csprng.h>
#include <ripple/crypto/secure_erase.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/digest.h>
#include <ripple/protocol/impl/secp256k1.h>
@@ -33,7 +33,7 @@ namespace ripple {
SecretKey::~SecretKey()
{
beast::secure_erase(buf_, sizeof(buf_));
secure_erase(buf_, sizeof(buf_));
}
SecretKey::SecretKey(std::array<std::uint8_t, 32> const& key)
@@ -86,8 +86,8 @@ public:
auto gpk = generatePublicDeterministicKey(gen_, ordinal);
SecretKey const sk(Slice{gsk.data(), gsk.size()});
PublicKey const pk(Slice{gpk.data(), gpk.size()});
beast::secure_erase(ui.data(), ui.size());
beast::secure_erase(gsk.data(), gsk.size());
secure_erase(ui.data(), ui.size());
secure_erase(gsk.data(), gsk.size());
return {pk, sk};
}
};
@@ -169,7 +169,7 @@ randomSecretKey()
std::uint8_t buf[32];
beast::rngfill(buf, sizeof(buf), crypto_prng());
SecretKey sk(Slice{buf, sizeof(buf)});
beast::secure_erase(buf, sizeof(buf));
secure_erase(buf, sizeof(buf));
return sk;
}
@@ -182,7 +182,7 @@ generateSecretKey(KeyType type, Seed const& seed)
{
auto key = sha512Half_s(Slice(seed.data(), seed.size()));
SecretKey sk = Slice{key.data(), key.size()};
beast::secure_erase(key.data(), key.size());
secure_erase(key.data(), key.size());
return sk;
}
@@ -194,7 +194,7 @@ generateSecretKey(KeyType type, Seed const& seed)
std::memcpy(ps.data(), seed.data(), seed.size());
auto const upk = generateRootDeterministicPrivateKey(ps);
SecretKey sk = Slice{upk.data(), upk.size()};
beast::secure_erase(ps.data(), ps.size());
secure_erase(ps.data(), ps.size());
return sk;
}

View File

@@ -19,10 +19,10 @@
#include <ripple/basics/Buffer.h>
#include <ripple/basics/contract.h>
#include <ripple/beast/crypto/secure_erase.h>
#include <ripple/beast/utility/rngfill.h>
#include <ripple/crypto/RFC1751.h>
#include <ripple/crypto/csprng.h>
#include <ripple/crypto/secure_erase.h>
#include <ripple/protocol/AccountID.h>
#include <ripple/protocol/PublicKey.h>
#include <ripple/protocol/SecretKey.h>
@@ -36,7 +36,7 @@ namespace ripple {
Seed::~Seed()
{
beast::secure_erase(buf_.data(), buf_.size());
secure_erase(buf_.data(), buf_.size());
}
Seed::Seed(Slice const& slice)
@@ -61,7 +61,7 @@ randomSeed()
std::array<std::uint8_t, 16> buffer;
beast::rngfill(buffer.data(), buffer.size(), crypto_prng());
Seed seed(makeSlice(buffer));
beast::secure_erase(buffer.data(), buffer.size());
secure_erase(buffer.data(), buffer.size());
return seed;
}

View File

@@ -25,17 +25,6 @@
namespace ripple {
int
Serializer::addZeros(size_t uBytes)
{
int ret = mData.size();
while (uBytes--)
mData.push_back(0);
return ret;
}
int
Serializer::add16(std::uint16_t i)
{
@@ -107,22 +96,6 @@ Serializer::addInteger(std::uint64_t i)
return add64(i);
}
int
Serializer::add128(const uint128& i)
{
int ret = mData.size();
mData.insert(mData.end(), i.begin(), i.end());
return ret;
}
int
Serializer::add256(uint256 const& i)
{
int ret = mData.size();
mData.insert(mData.end(), i.begin(), i.end());
return ret;
}
int
Serializer::addRaw(Blob const& vector)
{
@@ -147,16 +120,6 @@ Serializer::addRaw(const void* ptr, int len)
return ret;
}
bool
Serializer::get256(uint256& o, int offset) const
{
if ((offset + (256 / 8)) > mData.size())
return false;
memcpy(o.begin(), &(mData.front()) + offset, (256 / 8));
return true;
}
int
Serializer::addFieldID(int type, int name)
{
@@ -219,28 +182,6 @@ Serializer::chop(int bytes)
return true;
}
bool
Serializer::getRaw(Blob& o, int offset, int length) const
{
if ((offset + length) > mData.size())
return false;
o.assign(mData.begin() + offset, mData.begin() + offset + length);
return true;
}
Blob
Serializer::getRaw(int offset, int length) const
{
Blob o;
if ((offset + length) > mData.size())
return o;
o.assign(mData.begin() + offset, mData.begin() + offset + length);
return o;
}
uint256
Serializer::getSHA512Half() const
{
@@ -278,99 +219,6 @@ Serializer::addVL(const void* ptr, int len)
return ret;
}
bool
Serializer::getVL(Blob& objectVL, int offset, int& length) const
{
int b1;
if (!get8(b1, offset++))
return false;
int datLen, lenLen = decodeLengthLength(b1);
try
{
if (lenLen == 1)
datLen = decodeVLLength(b1);
else if (lenLen == 2)
{
int b2;
if (!get8(b2, offset++))
return false;
datLen = decodeVLLength(b1, b2);
}
else if (lenLen == 3)
{
int b2, b3;
if (!get8(b2, offset++))
return false;
if (!get8(b3, offset++))
return false;
datLen = decodeVLLength(b1, b2, b3);
}
else
return false;
}
catch (std::exception const&)
{
return false;
}
length = lenLen + datLen;
return getRaw(objectVL, offset, datLen);
}
bool
Serializer::getVLLength(int& length, int offset) const
{
int b1;
if (!get8(b1, offset++))
return false;
int lenLen = decodeLengthLength(b1);
try
{
if (lenLen == 1)
length = decodeVLLength(b1);
else if (lenLen == 2)
{
int b2;
if (!get8(b2, offset++))
return false;
length = decodeVLLength(b1, b2);
}
else if (lenLen == 3)
{
int b2, b3;
if (!get8(b2, offset++))
return false;
if (!get8(b3, offset++))
return false;
length = decodeVLLength(b1, b2, b3);
}
else
return false;
}
catch (std::exception const&)
{
return false;
}
return true;
}
int
Serializer::addEncoded(int length)
{

View File

@@ -21,20 +21,34 @@
#include <ripple/protocol/Serializer.h>
#include <ripple/protocol/SystemParameters.h>
#include <ripple/protocol/UintTypes.h>
#include <string_view>
namespace ripple {
// For details on the protocol-level serialization please visit
// https://xrpl.org/serialization.html#currency-codes
namespace detail {
// Characters we are willing to allow in the ASCII representation of a
// three-letter currency code.
constexpr std::string_view isoCharSet =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"<>(){}[]|?!@#$%^&*";
// The location (in bytes) of the 3 digit currency inside a 160-bit value
constexpr std::size_t isoCodeOffset = 12;
// The length of an ISO-4217 like code
constexpr std::size_t isoCodeLength = 3;
} // namespace detail
std::string
to_string(Currency const& currency)
{
// Characters we are willing to allow in the ASCII representation of a
// three-letter currency code.
static std::string const allowed_characters =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"0123456789"
"<>(){}[]|?!@#$%^&*";
if (currency == beast::zero)
return systemCurrencyCode();
@@ -46,16 +60,14 @@ to_string(Currency const& currency)
if ((currency & sIsoBits).isZero())
{
// The offset of the 3 character ISO code in the currency descriptor
int const isoOffset = 12;
std::string const iso(
currency.data() + isoOffset, currency.data() + isoOffset + 3);
currency.data() + detail::isoCodeOffset,
currency.data() + detail::isoCodeOffset + detail::isoCodeLength);
// Specifying the system currency code using ISO-style representation
// is not allowed.
if ((iso != systemCurrencyCode()) &&
(iso.find_first_not_of(allowed_characters) == std::string::npos))
(iso.find_first_not_of(detail::isoCharSet) == std::string::npos))
{
return iso;
}
@@ -73,30 +85,27 @@ to_currency(Currency& currency, std::string const& code)
return true;
}
static const int CURRENCY_CODE_LENGTH = 3;
if (code.size() == CURRENCY_CODE_LENGTH)
// Handle ISO-4217-like 3-digit character codes.
if (code.size() == detail::isoCodeLength)
{
Blob codeBlob(CURRENCY_CODE_LENGTH);
if (code.find_first_not_of(detail::isoCharSet) != std::string::npos)
return false;
std::transform(code.begin(), code.end(), codeBlob.begin(), [](auto c) {
return ::toupper(static_cast<unsigned char>(c));
});
currency = beast::zero;
Serializer s;
std::transform(
code.begin(),
code.end(),
currency.begin() + detail::isoCodeOffset,
[](auto c) {
return static_cast<unsigned char>(
::toupper(static_cast<unsigned char>(c)));
});
s.addZeros(96 / 8);
s.addRaw(codeBlob);
s.addZeros(16 / 8);
s.addZeros(24 / 8);
s.get160(currency, 0);
return true;
}
if (40 == code.size())
return currency.SetHex(code);
return false;
return currency.SetHexExact(code);
}
Currency