Address issues identified by external review:

* RIPD-1617, RIPD-1619, RIPD-1621:
  Verify serialized public keys more strictly before
  using them.

* RIPD-1618:
    * Simplify the base58 decoder logic.
    * Reduce the complexity of the base58 encoder and
      eliminate a potential out-of-bounds memory access.
    * Improve type safety by using an `enum class` to
      enforce strict type checking for token types.

* RIPD-1616:
  Avoid calling `memcpy` with a null pointer even if the
  size is specified as zero, since it results in undefined
  behavior.

Acknowledgements:
Ripple thanks Guido Vranken for responsibly disclosing these
issues.

Bug Bounties and Responsible Disclosures:
We welcome reviews of the rippled code and urge researchers
to responsibly disclose any issues that they may find. For
more on Ripple's Bug Bounty program, please visit:
https://ripple.com/bug-bounty
This commit is contained in:
Nikolaos D. Bougalis
2018-03-15 20:58:05 -07:00
parent 25de6b0a5f
commit d5f981f5fc
47 changed files with 393 additions and 264 deletions

View File

@@ -66,7 +66,7 @@ RCLCxPeerPos::getJson() const
auto ret = proposal().getJson();
if (publicKey().size())
ret[jss::peer_id] = toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey());
ret[jss::peer_id] = toBase58(TokenType::NodePublic, publicKey());
return ret;
}

View File

@@ -251,7 +251,7 @@ RCLValidationsAdaptor::doStaleWrite(ScopedLockType&)
auto const initialSeq = ledgerSeq.value_or(
app_.getLedgerMaster().getCurrentLedgerIndex());
auto const nodePubKey = toBase58(
TokenType::TOKEN_NODE_PUBLIC, val->getSignerPublic());
TokenType::NodePublic, val->getSignerPublic());
auto const signTime =
val->getSignTime().time_since_epoch().count();
@@ -300,10 +300,10 @@ handleNewValidation(Application& app,
s << "Val for " << hash
<< (val->isTrusted() ? " trusted/" : " UNtrusted/")
<< (val->isFull() ? "full" : "partial") << " from "
<< (masterKey ? toBase58(TokenType::TOKEN_NODE_PUBLIC, *masterKey)
<< (masterKey ? toBase58(TokenType::NodePublic, *masterKey)
: "unknown")
<< " signing key "
<< toBase58(TokenType::TOKEN_NODE_PUBLIC, signingKey) << " " << msg
<< toBase58(TokenType::NodePublic, signingKey) << " " << msg
<< " src=" << source;
};
@@ -346,7 +346,7 @@ handleNewValidation(Application& app,
else
{
JLOG(j.debug()) << "Val for " << hash << " from "
<< toBase58(TokenType::TOKEN_NODE_PUBLIC, signingKey)
<< toBase58(TokenType::NodePublic, signingKey)
<< " not added UNlisted";
}

View File

@@ -66,9 +66,9 @@ loadNodeIdentity (Application& app)
while (st.fetch ())
{
auto const sk = parseBase58<SecretKey>(
TOKEN_NODE_PRIVATE, priKO.value_or(""));
TokenType::NodePrivate, priKO.value_or(""));
auto const pk = parseBase58<PublicKey>(
TOKEN_NODE_PUBLIC, pubKO.value_or(""));
TokenType::NodePublic, pubKO.value_or(""));
// Only use if the public and secret keys are a pair
if (sk && pk && (*pk == derivePublicKey (KeyType::secp256k1, *sk)))
@@ -86,8 +86,8 @@ loadNodeIdentity (Application& app)
*db << str (boost::format (
"INSERT INTO NodeIdentity (PublicKey,PrivateKey) VALUES ('%s','%s');")
% toBase58 (TokenType::TOKEN_NODE_PUBLIC, *publicKey)
% toBase58 (TokenType::TOKEN_NODE_PRIVATE, *secretKey));
% toBase58 (TokenType::NodePublic, *publicKey)
% toBase58 (TokenType::NodePrivate, *secretKey));
}
return { *publicKey, *secretKey };

View File

@@ -784,7 +784,7 @@ void NetworkOPsImp::processClusterTimer ()
{
protocol::TMClusterNode& n = *cluster.add_clusternodes();
n.set_publickey(toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
node.identity()));
n.set_reporttime(
node.getReportTime().time_since_epoch().count());
@@ -1556,9 +1556,9 @@ void NetworkOPsImp::pubManifest (Manifest const& mo)
jvObj [jss::type] = "manifestReceived";
jvObj [jss::master_key] = toBase58(
TokenType::TOKEN_NODE_PUBLIC, mo.masterKey);
TokenType::NodePublic, mo.masterKey);
jvObj [jss::signing_key] = toBase58(
TokenType::TOKEN_NODE_PUBLIC, mo.signingKey);
TokenType::NodePublic, mo.signingKey);
jvObj [jss::seq] = Json::UInt (mo.sequence);
jvObj [jss::signature] = strHex (mo.getSignature ());
jvObj [jss::master_signature] = strHex (mo.getMasterSignature ());
@@ -1695,7 +1695,7 @@ void NetworkOPsImp::pubValidation (STValidation::ref val)
jvObj [jss::type] = "validationReceived";
jvObj [jss::validation_public_key] = toBase58(
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
val->getSignerPublic());
jvObj [jss::ledger_hash] = to_string (val->getLedgerHash ());
jvObj [jss::signature] = strHex (val->getSignature ());
@@ -2122,7 +2122,7 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
if (!app_.getValidationPublicKey().empty())
{
info[jss::pubkey_validator] = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
app_.validators().localPublicKey());
}
else
@@ -2132,7 +2132,7 @@ Json::Value NetworkOPsImp::getServerInfo (bool human, bool admin)
}
info[jss::pubkey_node] = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
app_.nodeIdentity().first);
info[jss::complete_ledgers] =
@@ -2820,7 +2820,7 @@ bool NetworkOPsImp::subServer (InfoSub::ref isrListener, Json::Value& jvResult,
jvResult[jss::load_factor] = feeTrack.getLoadFactor ();
jvResult [jss::hostid] = getHostId (admin);
jvResult[jss::pubkey_node] = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
app_.nodeIdentity().first);
ScopedLockType sl (mSubLock);

View File

@@ -57,10 +57,8 @@ Manifest::make_Manifest (std::string s)
auto const spk = st.getFieldVL (sfSigningPubKey);
if (! publicKeyType (makeSlice(spk)))
return boost::none;
auto const opt_sig = get (st, sfSignature);
if (! opt_sig)
if (! get (st, sfSignature))
return boost::none;
return Manifest (std::move (s), PublicKey (makeSlice(pk)),
PublicKey (makeSlice(spk)), *opt_seq);
}
@@ -83,7 +81,7 @@ logMftAct (
std::uint32_t seq)
{
s << "Manifest: " << action <<
";Pk: " << toBase58 (TokenType::TOKEN_NODE_PUBLIC, pk) <<
";Pk: " << toBase58 (TokenType::NodePublic, pk) <<
";Seq: " << seq << ";";
return s;
}
@@ -97,7 +95,7 @@ Stream& logMftAct (
std::uint32_t oldSeq)
{
s << "Manifest: " << action <<
";Pk: " << toBase58 (TokenType::TOKEN_NODE_PUBLIC, pk) <<
";Pk: " << toBase58 (TokenType::NodePublic, pk) <<
";Seq: " << seq <<
";OldSeq: " << oldSeq << ";";
return s;

View File

@@ -98,14 +98,14 @@ ValidatorList::load (
auto const ret = strUnHex (key);
if (! ret.second || ! ret.first.size ())
if (! ret.second || ! publicKeyType(makeSlice(ret.first)))
{
JLOG (j_.error()) <<
"Invalid validator list publisher key: " << key;
return false;
}
auto id = PublicKey(Slice{ ret.first.data (), ret.first.size() });
auto id = PublicKey(makeSlice(ret.first));
if (validatorManifests_.revoked (id))
{
@@ -154,7 +154,7 @@ ValidatorList::load (
}
auto const id = parseBase58<PublicKey>(
TokenType::TOKEN_NODE_PUBLIC, match[1]);
TokenType::NodePublic, match[1]);
if (!id)
{
@@ -230,7 +230,7 @@ ValidatorList::applyList (
std::pair<Blob, bool> ret (strUnHex (
val["validation_public_key"].asString ()));
if (! ret.second || ! ret.first.size ())
if (! ret.second || ! publicKeyType(makeSlice(ret.first)))
{
JLOG (j_.error()) <<
"Invalid node identity: " <<
@@ -440,7 +440,7 @@ ValidatorList::removePublisherList (PublicKey const& publisherKey)
JLOG (j_.debug()) <<
"Removing validator list for revoked publisher " <<
toBase58(TokenType::TOKEN_NODE_PUBLIC, publisherKey);
toBase58(TokenType::NodePublic, publisherKey);
for (auto const& val : iList->second.list)
{
@@ -506,7 +506,7 @@ ValidatorList::getJson() const
{
for (auto const& key : it->second.list)
jLocalStaticKeys.append(
toBase58(TokenType::TOKEN_NODE_PUBLIC, key));
toBase58(TokenType::NodePublic, key));
}
// Publisher lists
@@ -528,7 +528,7 @@ ValidatorList::getJson() const
Json::Value& keys = (curr[jss::list] = Json::arrayValue);
for (auto const& key : p.second.list)
{
keys.append(toBase58(TokenType::TOKEN_NODE_PUBLIC, key));
keys.append(toBase58(TokenType::NodePublic, key));
}
}
@@ -537,7 +537,7 @@ ValidatorList::getJson() const
(res[jss::trusted_validator_keys] = Json::arrayValue);
for (auto const& k : trustedKeys_)
{
jValidatorKeys.append(toBase58(TokenType::TOKEN_NODE_PUBLIC, k));
jValidatorKeys.append(toBase58(TokenType::NodePublic, k));
}
// signing keys
@@ -549,8 +549,8 @@ ValidatorList::getJson() const
if (it != keyListings_.end())
{
jSigningKeys[toBase58(
TokenType::TOKEN_NODE_PUBLIC, manifest.masterKey)] =
toBase58(TokenType::TOKEN_NODE_PUBLIC, manifest.signingKey);
TokenType::NodePublic, manifest.masterKey)] =
toBase58(TokenType::NodePublic, manifest.signingKey);
}
});

View File

@@ -348,7 +348,6 @@ PayChanClaim::preflight (PreflightContext const& ctx)
if (! ctx.rules.enabled(featurePayChan))
return temDISABLED;
bool const noTecs = ctx.rules.enabled(fix1512);
auto const ret = preflight1 (ctx);

View File

@@ -722,7 +722,7 @@ private:
std::string const strPk = jvParams[0u].asString ();
bool const validPublicKey = [&strPk]{
if (parseBase58<PublicKey> (TokenType::TOKEN_ACCOUNT_PUBLIC, strPk))
if (parseBase58<PublicKey> (TokenType::AccountPublic, strPk))
return true;
std::pair<Blob, bool> pkHex(strUnHex (strPk));
@@ -775,7 +775,7 @@ private:
if (i < 2)
{
if (parseBase58<PublicKey> (
TokenType::TOKEN_ACCOUNT_PUBLIC, strParam) ||
TokenType::AccountPublic, strParam) ||
parseBase58<AccountID> (strParam) ||
parseGenericSeed (strParam))
{
@@ -810,7 +810,7 @@ private:
--iCursor;
}
if (! parseBase58<PublicKey>(TokenType::TOKEN_ACCOUNT_PUBLIC, strIdent) &&
if (! parseBase58<PublicKey>(TokenType::AccountPublic, strIdent) &&
! parseBase58<AccountID>(strIdent) &&
! parseGenericSeed(strIdent))
return rpcError (rpcACT_MALFORMED);

View File

@@ -121,7 +121,7 @@ Cluster::load (Section const& nodes)
}
auto const id = parseBase58<PublicKey>(
TokenType::TOKEN_NODE_PUBLIC, match[1]);
TokenType::NodePublic, match[1]);
if (!id)
{

View File

@@ -363,7 +363,7 @@ ConnectAttempt::processResponse()
return close(); // verifyHello logs
JLOG(journal_.info()) <<
"Public Key: " << toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
*publicKey);
auto const protocol =

View File

@@ -424,7 +424,7 @@ OverlayImpl::add_active (std::shared_ptr<PeerImp> const& peer)
"activated " << peer->getRemoteAddress() <<
" (" << peer->id() << ":" <<
toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
peer->getNodePublic()) << ")";
// As we are not on the strand, run() must be called
@@ -610,7 +610,7 @@ OverlayImpl::activate (std::shared_ptr<PeerImp> const& peer)
"activated " << peer->getRemoteAddress() <<
" (" << peer->id() <<
":" << toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
peer->getNodePublic()) << ")";
// We just accepted this peer so we have non-zero active peers

View File

@@ -256,7 +256,7 @@ PeerImp::json()
Json::Value ret (Json::objectValue);
ret[jss::public_key] = toBase58 (
TokenType::TOKEN_NODE_PUBLIC, publicKey_);
TokenType::NodePublic, publicKey_);
ret[jss::address] = remote_address_.to_string();
if (m_inbound)
@@ -629,7 +629,7 @@ void PeerImp::doAccept()
JLOG(journal_.info()) << "Protocol: " << to_string(protocol);
JLOG(journal_.info()) <<
"Public Key: " << toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
publicKey_);
if (auto member = app_.cluster().member(publicKey_))
{
@@ -932,7 +932,7 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMCluster> const& m)
name = node.nodename();
auto const publicKey = parseBase58<PublicKey>(
TokenType::TOKEN_NODE_PUBLIC, node.publickey());
TokenType::NodePublic, node.publickey());
// NIKB NOTE We should drop the peer immediately if
// they send us a public key we can't parse
@@ -1610,8 +1610,7 @@ PeerImp::onMessage (std::shared_ptr <protocol::TMValidation> const& m)
STValidation::pointer val;
{
SerialIter sit (makeSlice(m->validation()));
val = std::make_shared <
STValidation> (std::ref (sit), false);
val = std::make_shared <STValidation> (std::ref (sit), false);
val->setSeen (closeTime);
}

View File

@@ -112,7 +112,7 @@ buildHello (
h.set_nettime (app.timeKeeper().now().time_since_epoch().count());
h.set_nodepublic (
toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
app.nodeIdentity().first));
h.set_nodeproof (sig.data(), sig.size());
// h.set_ipv4port (portNumber); // ignored now
@@ -247,7 +247,7 @@ parseHello (bool request, beast::http::fields const& h, beast::Journal journal)
if (iter == h.end())
return boost::none;
auto const pk = parseBase58<PublicKey>(
TokenType::TOKEN_NODE_PUBLIC, iter->value().to_string());
TokenType::NodePublic, iter->value().to_string());
if (!pk)
return boost::none;
hello.set_nodepublic (iter->value().to_string());
@@ -381,7 +381,7 @@ verifyHello (protocol::TMHello const& h,
}
auto const publicKey = parseBase58<PublicKey>(
TokenType::TOKEN_NODE_PUBLIC, h.nodepublic());
TokenType::NodePublic, h.nodepublic());
if (! publicKey)
{
@@ -390,6 +390,13 @@ verifyHello (protocol::TMHello const& h,
return boost::none;
}
if (publicKeyType(*publicKey) != KeyType::secp256k1)
{
JLOG(journal.info()) <<
"Hello: Disconnect: Unsupported public key type.";
return boost::none;
}
if (*publicKey == app.nodeIdentity().first)
{
JLOG(journal.info()) <<

View File

@@ -70,7 +70,7 @@ public:
/** Create a public key.
Preconditions:
publicKeyType(Slice(data, size)) != boost::none
publicKeyType(slice) != boost::none
*/
explicit
PublicKey (Slice const& slice);

View File

@@ -102,8 +102,7 @@ inline
std::string
toBase58 (Seed const& seed)
{
return base58EncodeToken(
TOKEN_FAMILY_SEED, seed.data(), seed.size());
return base58EncodeToken(TokenType::FamilySeed, seed.data(), seed.size());
}
}

View File

@@ -29,18 +29,14 @@ namespace ripple {
std::string
toBase58 (AccountID const& v)
{
return base58EncodeToken(
TOKEN_ACCOUNT_ID,
v.data(), v.size());
return base58EncodeToken(TokenType::AccountID, v.data(), v.size());
}
template<>
boost::optional<AccountID>
parseBase58 (std::string const& s)
{
auto const result =
decodeBase58Token(
s, TOKEN_ACCOUNT_ID);
auto const result = decodeBase58Token(s, TokenType::AccountID);
if (result.empty())
return boost::none;
AccountID id;
@@ -54,9 +50,7 @@ parseBase58 (std::string const& s)
boost::optional<AccountID>
deprecatedParseBitcoinAccountID (std::string const& s)
{
auto const result =
decodeBase58TokenBitcoin(
s, TOKEN_ACCOUNT_ID);
auto const result = decodeBase58TokenBitcoin(s, TokenType::AccountID);
if (result.empty())
return boost::none;
AccountID id;

View File

@@ -37,22 +37,15 @@ operator<<(std::ostream& os, PublicKey const& pk)
return os;
}
using uint264 = boost::multiprecision::number<
boost::multiprecision::cpp_int_backend<
264, 264, boost::multiprecision::signed_magnitude,
boost::multiprecision::unchecked, void>>;
template<>
boost::optional<PublicKey>
parseBase58 (TokenType type, std::string const& s)
{
auto const result =
decodeBase58Token(s, type);
if (result.empty())
auto const result = decodeBase58Token(s, type);
auto const pks = makeSlice(result);
if (!publicKeyType(pks))
return boost::none;
if (result.size() != 33)
return boost::none;
return PublicKey(makeSlice(result));
return PublicKey(pks);
}
//------------------------------------------------------------------------------
@@ -81,8 +74,7 @@ sigPart (Slice& buf)
if ((buf[1] & 0x80) == 0)
return boost::none;
}
boost::optional<Slice> number =
Slice(buf.data(), len);
boost::optional<Slice> number = Slice(buf.data(), len);
buf += len;
return number;
}
@@ -125,6 +117,11 @@ sliceToHex (Slice const& slice)
boost::optional<ECDSACanonicality>
ecdsaCanonicality (Slice const& sig)
{
using uint264 = boost::multiprecision::number<
boost::multiprecision::cpp_int_backend<
264, 264, boost::multiprecision::signed_magnitude,
boost::multiprecision::unchecked, void>>;
static uint264 const G(
"0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
@@ -141,12 +138,13 @@ ecdsaCanonicality (Slice const& sig)
return boost::none;
uint264 R(sliceToHex(*r));
uint264 S(sliceToHex(*s));
if (R >= G)
return boost::none;
uint264 S(sliceToHex(*s));
if (S >= G)
return boost::none;
// (R,S) and (R,G-S) are canonical,
// but is fully canonical when S <= G-S
auto const Sp = G - S;
@@ -186,7 +184,7 @@ PublicKey::PublicKey (Slice const& slice)
if(! publicKeyType(slice))
LogicError("PublicKey::PublicKey invalid type");
size_ = slice.size();
std::memcpy(buf_, slice.data(), slice.size());
std::memcpy(buf_, slice.data(), size_);
}
PublicKey::PublicKey (PublicKey const& other)
@@ -196,8 +194,7 @@ PublicKey::PublicKey (PublicKey const& other)
};
PublicKey&
PublicKey::operator=(
PublicKey const& other)
PublicKey::operator=(PublicKey const& other)
{
size_ = other.size_;
std::memcpy(buf_, other.buf_, size_);
@@ -209,13 +206,15 @@ PublicKey::operator=(
boost::optional<KeyType>
publicKeyType (Slice const& slice)
{
if (slice.size() == 33 &&
slice[0] == 0xED)
return KeyType::ed25519;
if (slice.size() == 33 &&
(slice[0] == 0x02 ||
slice[0] == 0x03))
return KeyType::secp256k1;
if (slice.size() == 33)
{
if (slice[0] == 0xED)
return KeyType::ed25519;
if (slice[0] == 0x02 || slice[0] == 0x03)
return KeyType::secp256k1;
}
return boost::none;
}

View File

@@ -29,15 +29,23 @@ namespace ripple {
STValidation::STValidation (SerialIter& sit, bool checkSignature)
: STObject (getFormat (), sit, sfValidation)
{
mNodeID = calcNodeID(
PublicKey(makeSlice (getFieldVL (sfSigningPubKey))));
auto const spk = getFieldVL(sfSigningPubKey);
if (publicKeyType(makeSlice(spk)) != KeyType::secp256k1)
{
JLOG (debugLog().error())
<< "Invalid public key in validation" << getJson (0);
Throw<std::runtime_error> ("Invalid public key in validation");
}
mNodeID = calcNodeID(PublicKey(makeSlice(spk)));
assert (mNodeID.isNonZero ());
if (checkSignature && !isValid ())
{
JLOG (debugLog().error())
<< "Invalid validation" << getJson (0);
Throw<std::runtime_error> ("Invalid validation");
<< "Invalid signature in validation" << getJson (0);
Throw<std::runtime_error> ("Invalid signature in validation");
}
}
@@ -49,11 +57,15 @@ STValidation::STValidation (
: STObject (getFormat (), sfValidation)
, mSeen (signTime)
{
// This is our own public key and it should always be valid.
if (!publicKeyType(publicKey))
LogicError ("Invalid validation public key");
// Does not sign
setFieldH256 (sfLedgerHash, ledgerHash);
setFieldU32 (sfSigningTime, signTime.time_since_epoch().count());
setFieldVL (sfSigningPubKey, publicKey.slice());
mNodeID = calcNodeID(publicKey);
assert (mNodeID.isNonZero ());
@@ -101,6 +113,9 @@ bool STValidation::isValid (uint256 const& signingHash) const
{
try
{
if (publicKeyType(getSignerPublic()) != KeyType::secp256k1)
return false;
return verifyDigest (getSignerPublic(),
signingHash,
makeSlice(getFieldVL (sfSignature)),

View File

@@ -87,10 +87,8 @@ public:
std::memcpy(ui.data(), seed.data(), seed.size());
auto gsk = generatePrivateDeterministicKey(gen_, ui, ordinal);
auto gpk = generatePublicDeterministicKey(gen_, ordinal);
SecretKey const sk(Slice
{ gsk.data(), gsk.size() });
PublicKey const pk(Slice
{ gpk.data(), gpk.size() });
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());
return {pk, sk};
@@ -243,7 +241,7 @@ derivePublicKey (KeyType type, SecretKey const& sk)
LogicError("derivePublicKey: secp256k1_ec_pubkey_create failed");
unsigned char pubkey[33];
size_t len = sizeof(pubkey);
std::size_t len = sizeof(pubkey);
if(secp256k1_ec_pubkey_serialize(
secp256k1Context(),
pubkey,
@@ -252,8 +250,7 @@ derivePublicKey (KeyType type, SecretKey const& sk)
SECP256K1_EC_COMPRESSED) != 1)
LogicError("derivePublicKey: secp256k1_ec_pubkey_serialize failed");
return PublicKey{Slice{pubkey,
static_cast<std::size_t>(len)}};
return PublicKey{Slice{ pubkey, len }};
}
case KeyType::ed25519:
{

View File

@@ -85,8 +85,7 @@ template <>
boost::optional<Seed>
parseBase58 (std::string const& s)
{
auto const result = decodeBase58Token(
s, TokenType::TOKEN_FAMILY_SEED);
auto const result = decodeBase58Token(s, TokenType::FamilySeed);
if (result.empty())
return boost::none;
if (result.size() != 16)
@@ -101,10 +100,10 @@ parseGenericSeed (std::string const& str)
return boost::none;
if (parseBase58<AccountID>(str) ||
parseBase58<PublicKey>(TokenType::TOKEN_NODE_PUBLIC, str) ||
parseBase58<PublicKey>(TokenType::TOKEN_ACCOUNT_PUBLIC, str) ||
parseBase58<SecretKey>(TokenType::TOKEN_NODE_PRIVATE, str) ||
parseBase58<SecretKey>(TokenType::TOKEN_ACCOUNT_SECRET, str))
parseBase58<PublicKey>(TokenType::NodePublic, str) ||
parseBase58<PublicKey>(TokenType::AccountPublic, str) ||
parseBase58<SecretKey>(TokenType::NodePrivate, str) ||
parseBase58<SecretKey>(TokenType::AccountSecret, str))
{
return boost::none;
}

View File

@@ -519,10 +519,16 @@ T SerialIter::getRawHelper (int size)
Throw<std::runtime_error> (
"invalid SerialIter getRaw");
T result (size);
memcpy(result.data (), p_, size);
p_ += size;
used_ += size;
remain_ -= size;
if (size != 0)
{
// It's normally safe to call memcpy with size set to 0 (see the
// C99 standard 7.21.1/2). However, here this could mean that
// result.data would be null, which would trigger undefined behavior.
std::memcpy(result.data(), p_, size);
p_ += size;
used_ += size;
remain_ -= size;
}
return result;
}

View File

@@ -20,6 +20,7 @@
#include <BeastConfig.h>
#include <ripple/protocol/tokens.h>
#include <ripple/protocol/digest.h>
#include <boost/container/small_vector.hpp>
#include <cassert>
#include <cstring>
#include <memory>
@@ -102,11 +103,12 @@ static
std::string
encodeBase58(
void const* message, std::size_t size,
void *temp, char const* const alphabet)
void *temp, std::size_t temp_size,
char const* const alphabet)
{
auto pbegin = reinterpret_cast<
unsigned char const*>(message);
auto pbegin = reinterpret_cast<unsigned char const*>(message);
auto const pend = pbegin + size;
// Skip & count leading zeroes.
int zeroes = 0;
while (pbegin != pend && *pbegin == 0)
@@ -114,12 +116,12 @@ encodeBase58(
pbegin++;
zeroes++;
}
auto const b58begin = reinterpret_cast<
unsigned char*>(temp);
// log(256) / log(58), rounded up.
auto const b58end = b58begin +
size * (138 / 100 + 1);
auto const b58begin = reinterpret_cast<unsigned char*>(temp);
auto const b58end = b58begin + temp_size;
std::fill(b58begin, b58end, 0);
while (pbegin != pend)
{
int carry = *pbegin;
@@ -133,10 +135,12 @@ encodeBase58(
assert(carry == 0);
pbegin++;
}
// Skip leading zeroes in base58 result.
auto iter = b58begin;
while (iter != b58end && *iter == 0)
++iter;
// Translate the result into a string.
std::string str;
str.reserve(zeroes + (b58end - iter));
@@ -148,48 +152,44 @@ encodeBase58(
static
std::string
encodeToken (std::uint8_t type,
void const* token, std::size_t size, bool btc)
encodeToken (TokenType type,
void const* token, std::size_t size, char const* const alphabet)
{
char buf[1024];
// expanded token includes type + checksum
// expanded token includes type + 4 byte checksum
auto const expanded = 1 + size + 4;
// add scratch, log(256) / log(58), rounded up.
auto const needed = expanded +
size * (138 / 100 + 1);
std::unique_ptr<
char[]> pbuf;
char* temp;
if (needed > sizeof(buf))
{
pbuf.reset(new char[needed]);
temp = pbuf.get();
}
else
{
temp = buf;
}
// We need expanded + expanded * (log(256) / log(58)) which is
// bounded by expanded + expanded * (138 / 100 + 1) which works
// out to expanded * 3:
auto const bufsize = expanded * 3;
boost::container::small_vector<std::uint8_t, 1024> buf (bufsize);
// Lay the data out as
// <type><token><checksum>
temp[0] = type;
std::memcpy(temp + 1, token, size);
checksum(temp + 1 + size, temp, 1 + size);
return encodeBase58(temp, expanded,
temp + expanded, btc ? bitcoinAlphabet : rippleAlphabet);
buf[0] = static_cast<std::underlying_type_t <TokenType>>(type);
if (size)
std::memcpy(buf.data() + 1, token, size);
checksum(buf.data() + 1 + size, buf.data(), 1 + size);
return encodeBase58(
buf.data(), expanded,
buf.data() + expanded, bufsize - expanded,
alphabet);
}
std::string
base58EncodeToken (std::uint8_t type,
base58EncodeToken (TokenType type,
void const* token, std::size_t size)
{
return encodeToken(type, token, size, false);
return encodeToken(type, token, size, rippleAlphabet);
}
std::string
base58EncodeTokenBitcoin (std::uint8_t type,
base58EncodeTokenBitcoin (TokenType type,
void const* token, std::size_t size)
{
return encodeToken(type, token, size, true);
return encodeToken(type, token, size, bitcoinAlphabet);
}
//------------------------------------------------------------------------------
@@ -258,28 +258,26 @@ template <class InverseArray>
static
std::string
decodeBase58Token (std::string const& s,
int type, InverseArray const& inv)
TokenType type, InverseArray const& inv)
{
auto result = decodeBase58(s, inv);
if (result.empty())
return result;
auto ret = decodeBase58(s, inv);
// Reject zero length tokens
if (result.size() < 6)
if (ret.size() < 6)
return {};
if (result[0] != type)
// The type must match.
if (type != static_cast<TokenType>(ret[0]))
return {};
// And the checksum must as well.
std::array<char, 4> guard;
checksum(guard.data(),
result.data(), result.size() - 4);
if (std::memcmp(guard.data(),
result.data() +
result.size() - 4, 4) != 0)
checksum(guard.data(), ret.data(), ret.size() - guard.size());
if (!std::equal (guard.rbegin(), guard.rend(), ret.rbegin()))
return {};
result.resize(result.size() - 4);
// Erase the type byte
// VFALCO This might cause problems later
result.erase(result.begin());
return result;
// Skip the leading type byte and the trailing checksum.
return ret.substr(1, ret.size() - 1 - guard.size());
}
//------------------------------------------------------------------------------
@@ -315,18 +313,16 @@ static InverseAlphabet bitcoinInverse(bitcoinAlphabet);
std::string
decodeBase58Token(
std::string const& s, int type)
std::string const& s, TokenType type)
{
return decodeBase58Token(
s, type, rippleInverse);
return decodeBase58Token(s, type, rippleInverse);
}
std::string
decodeBase58TokenBitcoin(
std::string const& s, int type)
std::string const& s, TokenType type)
{
return decodeBase58Token(
s, type, bitcoinInverse);
return decodeBase58Token(s, type, bitcoinInverse);
}
} // ripple

View File

@@ -26,16 +26,16 @@
namespace ripple {
enum TokenType
enum class TokenType : std::uint8_t
{
TOKEN_NONE = 1,
TOKEN_NODE_PUBLIC = 28,
TOKEN_NODE_PRIVATE = 32,
TOKEN_ACCOUNT_ID = 0,
TOKEN_ACCOUNT_PUBLIC = 35,
TOKEN_ACCOUNT_SECRET = 34,
TOKEN_FAMILY_GENERATOR = 41,
TOKEN_FAMILY_SEED = 33
None = 1, // unused
NodePublic = 28,
NodePrivate = 32,
AccountID = 0,
AccountPublic = 35,
AccountSecret = 34,
FamilyGenerator = 41, // unused
FamilySeed = 33
};
template <class T>
@@ -75,8 +75,7 @@ parseHexOrBase58 (std::string const& s);
@param size the size of the token buffer in bytes
*/
std::string
base58EncodeToken (std::uint8_t type,
void const* token, std::size_t size);
base58EncodeToken (TokenType type, void const* token, std::size_t size);
/* Base-58 encode a Bitcoin Token
*
@@ -87,8 +86,7 @@ base58EncodeToken (std::uint8_t type,
*
*/
std::string
base58EncodeTokenBitcoin (std::uint8_t type,
void const* token, std::size_t size);
base58EncodeTokenBitcoin (TokenType type, void const* token, std::size_t size);
/** Decode a Base58 token
@@ -96,8 +94,7 @@ base58EncodeTokenBitcoin (std::uint8_t type,
empty string is returned.
*/
std::string
decodeBase58Token(
std::string const& s, int type);
decodeBase58Token(std::string const& s, TokenType type);
/** Decode a Base58 token using Bitcoin alphabet
@@ -110,8 +107,7 @@ decodeBase58Token(
may be returned.
*/
std::string
decodeBase58TokenBitcoin(
std::string const& s, int type);
decodeBase58TokenBitcoin(std::string const& s, TokenType type);
} // ripple

View File

@@ -43,7 +43,7 @@ void addChannel (Json::Value& jsonLines, SLE const& line)
if (publicKeyType(line[sfPublicKey]))
{
PublicKey const pk (line[sfPublicKey]);
jDst[jss::public_key] = toBase58 (TokenType::TOKEN_ACCOUNT_PUBLIC, pk);
jDst[jss::public_key] = toBase58 (TokenType::AccountPublic, pk);
jDst[jss::public_key_hex] = strHex (pk);
}
jDst[jss::settle_delay] = line[sfSettleDelay];

View File

@@ -93,7 +93,7 @@ Json::Value doGatewayBalances (RPC::Context& context)
if (j.isString())
{
auto const pk = parseBase58<PublicKey>(
TokenType::TOKEN_ACCOUNT_PUBLIC,
TokenType::AccountPublic,
j.asString ());
if (pk)
{

View File

@@ -126,7 +126,7 @@ Json::Value doChannelVerify (RPC::Context& context)
boost::optional<PublicKey> pk;
{
std::string const strPk = params[jss::public_key].asString();
pk = parseBase58<PublicKey>(TokenType::TOKEN_ACCOUNT_PUBLIC, strPk);
pk = parseBase58<PublicKey>(TokenType::AccountPublic, strPk);
if (!pk)
{

View File

@@ -52,7 +52,7 @@ Json::Value doPeers (RPC::Context& context)
Json::Value& json = cluster[
toBase58(
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
node.identity())];
if (!node.name().empty())

View File

@@ -39,7 +39,7 @@ Json::Value doUnlList (RPC::Context& context)
Json::Value node (Json::objectValue);
node[jss::pubkey_validator] = toBase58(
TokenType::TOKEN_NODE_PUBLIC, publicKey);
TokenType::NodePublic, publicKey);
node[jss::trusted] = trusted;
unl.append (node);

View File

@@ -55,11 +55,11 @@ Json::Value doValidationCreate (RPC::Context& context)
auto const private_key = generateSecretKey (KeyType::secp256k1, *seed);
obj[jss::validation_public_key] = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
derivePublicKey (KeyType::secp256k1, private_key));
obj[jss::validation_private_key] = toBase58 (
TokenType::TOKEN_NODE_PRIVATE, private_key);
TokenType::NodePrivate, private_key);
obj[jss::validation_seed] = toBase58 (*seed);
obj[jss::validation_key] = seedAs1751 (*seed);

View File

@@ -116,7 +116,7 @@ Json::Value walletPropose (Json::Value const& params)
obj[jss::master_seed_hex] = seedHex;
obj[jss::master_key] = seed1751;
obj[jss::account_id] = toBase58(calcAccountID(publicKey));
obj[jss::public_key] = toBase58(TOKEN_ACCOUNT_PUBLIC, publicKey);
obj[jss::public_key] = toBase58(TokenType::AccountPublic, publicKey);
obj[jss::key_type] = to_string (keyType);
obj[jss::public_key_hex] = strHex (publicKey.data(), publicKey.size());

View File

@@ -36,7 +36,7 @@ accountFromStringStrict(std::string const& account)
boost::optional <AccountID> result;
auto const publicKey = parseBase58<PublicKey> (
TokenType::TOKEN_ACCOUNT_PUBLIC,
TokenType::AccountPublic,
account);
if (publicKey)

View File

@@ -251,7 +251,7 @@ public:
std::string cfgManifest;
for (auto const& man : inManifests)
s1.push_back (toBase58(
TokenType::TOKEN_NODE_PUBLIC, man->masterKey));
TokenType::NodePublic, man->masterKey));
unl->load (emptyLocalKey, s1, keys);
m.save (dbCon, "ValidatorManifests",
@@ -428,7 +428,7 @@ public:
{
auto const valSecret = parseBase58<SecretKey>(
TokenType::TOKEN_NODE_PRIVATE,
TokenType::NodePrivate,
"paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi");
// Format token string to test trim()

View File

@@ -1065,8 +1065,21 @@ struct PayChan_test : public beast::unit_test::suite
jv.removeMember("PublicKey");
env (jv, ter(temMALFORMED));
jv["PublicKey"] = pkHex;
env (jv);
{
auto const txn = R"*(
{
"channel_id":"5DB01B7FFED6B67E6B0414DED11E051D2EE2B7619CE0EAA6286D67A3A4D5BDB3",
"signature":
"304402204EF0AFB78AC23ED1C472E74F4299C0C21F1B21D07EFC0A3838A420F76D783A400220154FB11B6F54320666E4C36CA7F686C16A3A0456800BBC43746F34AF50290064",
"public_key":
"aKijDDiC2q2gXjMpM7i4BUS6cmixgsEe18e7CjsUxwihKfuoFgS5",
"amount": "1000000"
}
)*";
auto const r = env.rpc("json", "channel_verify", txn);
BEAST_EXPECT(r["result"]["error"] == "publicMalformed");
}
}
void

View File

@@ -82,7 +82,7 @@ public:
// Keys when using [validation_token]
auto const tokenSecretKey = *parseBase58<SecretKey>(
TokenType::TOKEN_NODE_PRIVATE, tokenSecretStr);
TokenType::NodePrivate, tokenSecretStr);
auto const tokenPublicKey =
derivePublicKey(KeyType::secp256k1, tokenSecretKey);

View File

@@ -172,7 +172,7 @@ private:
PublicKey const &publicKey,
char const* comment = nullptr)
{
auto ret = toBase58 (TokenType::TOKEN_NODE_PUBLIC, publicKey);
auto ret = toBase58 (TokenType::NodePublic, publicKey);
if (comment)
ret += comment;
@@ -271,7 +271,7 @@ private:
manifests, manifests, env.timeKeeper(), journal);
auto const localSigningPublic = parseBase58<PublicKey> (
TokenType::TOKEN_NODE_PUBLIC, cfgKeys.front());
TokenType::NodePublic, cfgKeys.front());
BEAST_EXPECT(trustedKeys->load (
*localSigningPublic, cfgKeys, emptyCfgPublishers));
@@ -330,7 +330,7 @@ private:
badPublishers.clear();
for (auto const& key : keys)
badPublishers.push_back (
toBase58 (TokenType::TOKEN_NODE_PUBLIC, key));
toBase58 (TokenType::NodePublic, key));
BEAST_EXPECT(! trustedKeys->load (
emptyLocalKey, emptyCfgKeys, badPublishers));
@@ -533,7 +533,7 @@ private:
{
auto const valKey = randomNode();
cfgKeys.push_back (toBase58(
TokenType::TOKEN_NODE_PUBLIC, valKey));
TokenType::NodePublic, valKey));
if (cfgKeys.size () <= n - 5)
activeValidators.emplace (valKey);
}
@@ -550,7 +550,7 @@ private:
for (auto const& val : cfgKeys)
{
if (auto const valKey = parseBase58<PublicKey>(
TokenType::TOKEN_NODE_PUBLIC, val))
TokenType::NodePublic, val))
{
BEAST_EXPECT(trustedKeys->listed (*valKey));
if (i++ < activeValidators.size ())
@@ -567,7 +567,7 @@ private:
hash_set<PublicKey> activeValidators;
for (auto const valKey : cfgKeys)
activeValidators.emplace (*parseBase58<PublicKey>(
TokenType::TOKEN_NODE_PUBLIC, valKey));
TokenType::NodePublic, valKey));
trustedKeys->onConsensusStart (activeValidators);
BEAST_EXPECT(trustedKeys->quorum () == cfgKeys.size() * 4/5);
}
@@ -579,7 +579,7 @@ private:
derivePublicKey(KeyType::ed25519, masterPrivate);
std::vector<std::string> cfgKeys ({
toBase58 (TokenType::TOKEN_NODE_PUBLIC, masterPublic)});
toBase58 (TokenType::NodePublic, masterPublic)});
BEAST_EXPECT(trustedKeys->load (
emptyLocalKey, cfgKeys, cfgPublishers));
@@ -682,8 +682,8 @@ private:
std::vector<PublicKey> keys ({ randomNode (), randomNode () });
hash_set<PublicKey> activeValidators;
std::vector<std::string> cfgKeys ({
toBase58 (TokenType::TOKEN_NODE_PUBLIC, keys[0]),
toBase58 (TokenType::TOKEN_NODE_PUBLIC, keys[1])});
toBase58 (TokenType::NodePublic, keys[0]),
toBase58 (TokenType::NodePublic, keys[1])});
BEAST_EXPECT(trustedKeys->load (
emptyLocalKey, cfgKeys, cfgPublishers));
@@ -703,7 +703,7 @@ private:
auto const node = randomNode ();
std::vector<std::string> cfgKeys ({
toBase58 (TokenType::TOKEN_NODE_PUBLIC, node)});
toBase58 (TokenType::NodePublic, node)});
hash_set<PublicKey> activeValidators;
BEAST_EXPECT(trustedKeys->load (
@@ -724,8 +724,8 @@ private:
std::vector<PublicKey> keys ({ randomNode (), randomNode () });
hash_set<PublicKey> activeValidators ({ keys[0] });
std::vector<std::string> cfgKeys ({
toBase58 (TokenType::TOKEN_NODE_PUBLIC, keys[0]),
toBase58 (TokenType::TOKEN_NODE_PUBLIC, keys[1])});
toBase58 (TokenType::NodePublic, keys[0]),
toBase58 (TokenType::NodePublic, keys[1])});
auto const localKey = randomNode ();
BEAST_EXPECT(trustedKeys->load (
@@ -827,7 +827,7 @@ private:
{
auto const valKey = randomNode();
cfgKeys.push_back (toBase58(
TokenType::TOKEN_NODE_PUBLIC, valKey));
TokenType::NodePublic, valKey));
activeValidators.emplace (valKey);
BEAST_EXPECT(trustedKeys->load (
@@ -850,14 +850,14 @@ private:
hash_set<PublicKey> activeValidators;
std::vector<std::string> cfgKeys {
toBase58(TokenType::TOKEN_NODE_PUBLIC, localKey)};
toBase58(TokenType::NodePublic, localKey)};
cfgKeys.reserve(9);
while (cfgKeys.size() < cfgKeys.capacity())
{
auto const valKey = randomNode();
cfgKeys.push_back (toBase58(
TokenType::TOKEN_NODE_PUBLIC, valKey));
TokenType::NodePublic, valKey));
activeValidators.emplace (valKey);
BEAST_EXPECT(trustedKeys->load (
@@ -950,7 +950,7 @@ private:
jtx::Env env(*this);
auto toStr = [](PublicKey const& publicKey) {
return toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey);
return toBase58(TokenType::NodePublic, publicKey);
};
// Config listed keys

View File

@@ -133,7 +133,7 @@ public:
auto const node = randomNode ();
auto const name = toBase58(
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
node);
std::uint32_t load = 0;
NetClock::time_point tick = {};
@@ -202,7 +202,7 @@ public:
char const* comment = nullptr)
{
auto ret = toBase58(
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
publicKey);
if (comment)

View File

@@ -231,12 +231,12 @@ public:
void testBase58 (KeyType keyType)
{
// Try converting short, long and malformed data
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, ""));
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, " "));
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, "!ty89234gh45"));
BEAST_EXPECT(!parseBase58<PublicKey> (TokenType::NodePublic, ""));
BEAST_EXPECT(!parseBase58<PublicKey> (TokenType::NodePublic, " "));
BEAST_EXPECT(!parseBase58<PublicKey> (TokenType::NodePublic, "!ty89234gh45"));
auto const good = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
derivePublicKey (
keyType,
randomSecretKey()));
@@ -251,7 +251,7 @@ public:
while (!s.empty())
{
s.erase (r(s) % s.size(), 1);
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, s));
BEAST_EXPECT(!parseBase58<PublicKey> (TokenType::NodePublic, s));
}
}
@@ -260,7 +260,7 @@ public:
{
auto s = good;
s.resize (s.size() + i, s[i % s.size()]);
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, s));
BEAST_EXPECT(!parseBase58<PublicKey> (TokenType::NodePublic, s));
}
// Strings with invalid Base58 characters
@@ -270,7 +270,7 @@ public:
{
auto s = good;
s[i % s.size()] = c;
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, s));
BEAST_EXPECT(!parseBase58<PublicKey> (TokenType::NodePublic, s));
}
}
@@ -281,7 +281,7 @@ public:
for (auto c : std::string("apsrJqtv7"))
{
s[0] = c;
BEAST_EXPECT(!parseBase58<PublicKey> (TOKEN_NODE_PUBLIC, s));
BEAST_EXPECT(!parseBase58<PublicKey> (TokenType::NodePublic, s));
}
}
@@ -294,12 +294,12 @@ public:
for (std::size_t i = 0; i != keys.size(); ++i)
{
auto const si = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
keys[i]);
BEAST_EXPECT(!si.empty());
auto const ski = parseBase58<PublicKey> (
TOKEN_NODE_PUBLIC, si);
TokenType::NodePublic, si);
BEAST_EXPECT(ski && (keys[i] == *ski));
for (std::size_t j = i; j != keys.size(); ++j)
@@ -307,13 +307,13 @@ public:
BEAST_EXPECT((keys[i] == keys[j]) == (i == j));
auto const sj = toBase58 (
TokenType::TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
keys[j]);
BEAST_EXPECT((si == sj) == (i == j));
auto const skj = parseBase58<PublicKey> (
TOKEN_NODE_PUBLIC, sj);
TokenType::NodePublic, sj);
BEAST_EXPECT(skj && (keys[j] == *skj));
BEAST_EXPECT((*ski == *skj) == (i == j));
@@ -333,7 +333,7 @@ public:
generateSeed ("masterpassphrase")));
auto const pk2 = parseBase58<PublicKey> (
TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
"n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9");
BEAST_EXPECT(pk2);
@@ -352,7 +352,7 @@ public:
generateSeed ("masterpassphrase")));
auto const pk2 = parseBase58<PublicKey> (
TOKEN_NODE_PUBLIC,
TokenType::NodePublic,
"nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf");
BEAST_EXPECT(pk2);

View File

@@ -0,0 +1,111 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2012, 2013 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <BeastConfig.h>
#include <ripple/basics/Log.h>
#include <ripple/protocol/JsonFields.h>
#include <ripple/protocol/SecretKey.h>
#include <ripple/protocol/st.h>
#include <ripple/json/json_reader.h>
#include <ripple/json/to_string.h>
#include <ripple/beast/unit_test.h>
#include <test/jtx.h>
#include <memory>
#include <type_traits>
namespace ripple {
class STValidation_test : public beast::unit_test::suite
{
public:
void testDeserialization ()
{
testcase ("Deserialization");
constexpr unsigned char payload1[] =
{ // specifies an Ed25519 public key
0x72, 0x00, 0x73, 0x21, 0xed, 0x78, 0x00, 0xe6, 0x73, 0x00, 0x72, 0x00, 0x3c, 0x00, 0x00, 0x00,
0x88, 0x00, 0xe6, 0x73, 0x38, 0x00, 0x00, 0x8a, 0x00, 0x88, 0x4e, 0x31, 0x30, 0x5f, 0x5f, 0x63,
0x78, 0x78, 0x61, 0x62, 0x69, 0x76, 0x31, 0x30, 0x37, 0x5f, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73,
0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x45, 0x00, 0xe6, 0x88, 0x54, 0x72,
0x75, 0x73, 0x74, 0x53, 0x65, 0x74, 0x65, 0x61, 0x74, 0x65, 0x88, 0x00, 0xe6, 0x88, 0x00, 0xe6,
0x73, 0x00, 0x72, 0x00, 0x8a, 0x00, 0x88, 0x00, 0xe6
};
constexpr unsigned char payload2[] =
{
0x73, 0x21, 0xed, 0xff, 0x03, 0x1c, 0xbe, 0x65, 0x22, 0x61, 0x9c, 0x5e, 0x13, 0x12, 0x00, 0x3b,
0x43, 0x00, 0x00, 0x00, 0xf7, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x13, 0x13, 0x13,
0x3a, 0x27, 0xff
};
constexpr unsigned char payload3[] =
{ // Has no public key at all
0x72, 0x00, 0x76, 0x31, 0x30, 0x37, 0x5f, 0x5f, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x5f, 0x74, 0x79,
0x70, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x45, 0x00, 0xe6, 0x88, 0x54, 0x72, 0x75, 0x73, 0x74,
0x53, 0x65, 0x74, 0x65, 0x61, 0x74, 0x65, 0x88, 0x00, 0xe6, 0x88, 0x00, 0xe6, 0x73, 0x00, 0x72,
0x00, 0x8a, 0x00, 0x88, 0x00, 0xe6
};
try
{
SerialIter sit{payload1, sizeof(payload1)};
auto stx = std::make_shared<ripple::STValidation>(sit);
fail("An exception should have been thrown");
}
catch (std::exception const& e)
{
BEAST_EXPECT(strcmp(e.what(), "Invalid public key in validation") == 0);
}
try
{
SerialIter sit{payload2, sizeof(payload2)};
auto stx = std::make_shared<ripple::STValidation>(sit);
fail("An exception should have been thrown");
}
catch (std::exception const& e)
{
BEAST_EXPECT(strcmp(e.what(), "Invalid public key in validation") == 0);
}
try
{
SerialIter sit{payload3, sizeof(payload3)};
auto stx = std::make_shared<ripple::STValidation>(sit);
fail("An exception should have been thrown");
}
catch (std::exception const& e)
{
log << e.what() << "\n";
BEAST_EXPECT(strcmp(e.what(), "Invalid public key in validation") == 0);
}
}
void
run()
{
testDeserialization();
}
};
BEAST_DEFINE_TESTSUITE(STValidation,protocol,ripple);
} // ripple

View File

@@ -320,7 +320,7 @@ public:
generateSeed ("masterpassphrase"));
auto const sk2 = parseBase58<SecretKey> (
TOKEN_NODE_PRIVATE,
TokenType::NodePrivate,
"pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe");
BEAST_EXPECT(sk2);
@@ -333,7 +333,7 @@ public:
generateSeed ("masterpassphrase"));
auto const sk2 = parseBase58<SecretKey> (
TOKEN_NODE_PRIVATE,
TokenType::NodePrivate,
"paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36");
BEAST_EXPECT(sk2);
@@ -341,12 +341,12 @@ public:
}
// Try converting short, long and malformed data
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, ""));
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, " "));
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, "!35gty9mhju8nfjl"));
BEAST_EXPECT(!parseBase58<SecretKey> (TokenType::NodePrivate, ""));
BEAST_EXPECT(!parseBase58<SecretKey> (TokenType::NodePrivate, " "));
BEAST_EXPECT(!parseBase58<SecretKey> (TokenType::NodePrivate, "!35gty9mhju8nfjl"));
auto const good = toBase58 (
TokenType::TOKEN_NODE_PRIVATE,
TokenType::NodePrivate,
randomSecretKey());
// Short (non-empty) strings
@@ -359,7 +359,7 @@ public:
while (!s.empty())
{
s.erase (r(s) % s.size(), 1);
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, s));
BEAST_EXPECT(!parseBase58<SecretKey> (TokenType::NodePrivate, s));
}
}
@@ -368,7 +368,7 @@ public:
{
auto s = good;
s.resize (s.size() + i, s[i % s.size()]);
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, s));
BEAST_EXPECT(!parseBase58<SecretKey> (TokenType::NodePrivate, s));
}
// Strings with invalid Base58 characters
@@ -378,7 +378,7 @@ public:
{
auto s = good;
s[i % s.size()] = c;
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, s));
BEAST_EXPECT(!parseBase58<SecretKey> (TokenType::NodePrivate, s));
}
}
@@ -389,7 +389,7 @@ public:
for (auto c : std::string("ansrJqtv7"))
{
s[0] = c;
BEAST_EXPECT(!parseBase58<SecretKey> (TOKEN_NODE_PRIVATE, s));
BEAST_EXPECT(!parseBase58<SecretKey> (TokenType::NodePrivate, s));
}
}
@@ -402,12 +402,12 @@ public:
for (std::size_t i = 0; i != keys.size(); ++i)
{
auto const si = toBase58 (
TokenType::TOKEN_NODE_PRIVATE,
TokenType::NodePrivate,
keys[i]);
BEAST_EXPECT(!si.empty());
auto const ski = parseBase58<SecretKey> (
TOKEN_NODE_PRIVATE, si);
TokenType::NodePrivate, si);
BEAST_EXPECT(ski && keys[i] == *ski);
for (std::size_t j = i; j != keys.size(); ++j)
@@ -415,13 +415,13 @@ public:
BEAST_EXPECT((keys[i] == keys[j]) == (i == j));
auto const sj = toBase58 (
TokenType::TOKEN_NODE_PRIVATE,
TokenType::NodePrivate,
keys[j]);
BEAST_EXPECT((si == sj) == (i == j));
auto const skj = parseBase58<SecretKey> (
TOKEN_NODE_PRIVATE, sj);
TokenType::NodePrivate, sj);
BEAST_EXPECT(skj && keys[j] == *skj);
BEAST_EXPECT((*ski == *skj) == (i == j));

View File

@@ -136,9 +136,9 @@ public:
auto const publicKey = derivePublicKey (
KeyType::secp256k1, secretKey);
BEAST_EXPECT(toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey) ==
BEAST_EXPECT(toBase58(TokenType::NodePublic, publicKey) ==
"n94a1u4jAz288pZLtw6yFWVbi89YamiC6JBXPVUj5zmExe5fTVg9");
BEAST_EXPECT(toBase58(TokenType::TOKEN_NODE_PRIVATE, secretKey) ==
BEAST_EXPECT(toBase58(TokenType::NodePrivate, secretKey) ==
"pnen77YEeUd4fFKG7iycBWcwKpTaeFRkW2WFostaATy1DSupwXe");
BEAST_EXPECT(to_string(calcNodeID(publicKey)) ==
"7E59C17D50F5959C7B158FEC95C8F815BF653DC8");
@@ -179,9 +179,9 @@ public:
auto const publicKey = derivePublicKey (
KeyType::ed25519, secretKey);
BEAST_EXPECT(toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey) ==
BEAST_EXPECT(toBase58(TokenType::NodePublic, publicKey) ==
"nHUeeJCSY2dM71oxM8Cgjouf5ekTuev2mwDpc374aLMxzDLXNmjf");
BEAST_EXPECT(toBase58(TokenType::TOKEN_NODE_PRIVATE, secretKey) ==
BEAST_EXPECT(toBase58(TokenType::NodePrivate, secretKey) ==
"paKv46LztLqK3GaKz1rG2nQGN6M4JLyRtxFBYFTw4wAVHtGys36");
BEAST_EXPECT(to_string(calcNodeID(publicKey)) ==
"AA066C988C712815CC37AF71472B7CBBBD4E2A0A");
@@ -223,9 +223,9 @@ public:
BEAST_EXPECT(toBase58(calcAccountID(keyPair.first)) ==
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh");
BEAST_EXPECT(toBase58(TokenType::TOKEN_ACCOUNT_PUBLIC, keyPair.first) ==
BEAST_EXPECT(toBase58(TokenType::AccountPublic, keyPair.first) ==
"aBQG8RQAzjs1eTKFEAQXr2gS4utcDiEC9wmi7pfUPTi27VCahwgw");
BEAST_EXPECT(toBase58(TokenType::TOKEN_ACCOUNT_SECRET, keyPair.second) ==
BEAST_EXPECT(toBase58(TokenType::AccountSecret, keyPair.second) ==
"p9JfM6HHi64m6mvB6v5k7G2b1cXzGmYiCNJf6GHPKvFTWdeRVjh");
auto sig = sign (keyPair.first, keyPair.second, makeSlice(message1));
@@ -263,9 +263,9 @@ public:
BEAST_EXPECT(to_string(calcAccountID(keyPair.first)) ==
"rGWrZyQqhTp9Xu7G5Pkayo7bXjH4k4QYpf");
BEAST_EXPECT(toBase58(TokenType::TOKEN_ACCOUNT_PUBLIC, keyPair.first) ==
BEAST_EXPECT(toBase58(TokenType::AccountPublic, keyPair.first) ==
"aKGheSBjmCsKJVuLNKRAKpZXT6wpk2FCuEZAXJupXgdAxX5THCqR");
BEAST_EXPECT(toBase58(TokenType::TOKEN_ACCOUNT_SECRET, keyPair.second) ==
BEAST_EXPECT(toBase58(TokenType::AccountSecret, keyPair.second) ==
"pwDQjwEhbUBmPuEjFpEG75bFhv2obkCB7NxQsfFxM7xGHBMVPu9");
auto sig = sign (keyPair.first, keyPair.second, makeSlice(message1));
@@ -305,16 +305,16 @@ public:
auto const node1 = randomKeyPair(KeyType::secp256k1);
BEAST_EXPECT(!parseGenericSeed (
toBase58 (TokenType::TOKEN_NODE_PUBLIC, node1.first)));
toBase58 (TokenType::NodePublic, node1.first)));
BEAST_EXPECT(!parseGenericSeed (
toBase58 (TokenType::TOKEN_NODE_PRIVATE, node1.second)));
toBase58 (TokenType::NodePrivate, node1.second)));
auto const node2 = randomKeyPair(KeyType::ed25519);
BEAST_EXPECT(!parseGenericSeed (
toBase58 (TokenType::TOKEN_NODE_PUBLIC, node2.first)));
toBase58 (TokenType::NodePublic, node2.first)));
BEAST_EXPECT(!parseGenericSeed (
toBase58 (TokenType::TOKEN_NODE_PRIVATE, node2.second)));
toBase58 (TokenType::NodePrivate, node2.second)));
auto const account1 = generateKeyPair(
KeyType::secp256k1, randomSeed ());
@@ -322,9 +322,9 @@ public:
BEAST_EXPECT(!parseGenericSeed (
toBase58(calcAccountID(account1.first))));
BEAST_EXPECT(!parseGenericSeed (
toBase58(TokenType::TOKEN_ACCOUNT_PUBLIC, account1.first)));
toBase58(TokenType::AccountPublic, account1.first)));
BEAST_EXPECT(!parseGenericSeed (
toBase58(TokenType::TOKEN_ACCOUNT_SECRET, account1.second)));
toBase58(TokenType::AccountSecret, account1.second)));
auto const account2 = generateKeyPair(
KeyType::ed25519, randomSeed ());
@@ -332,9 +332,9 @@ public:
BEAST_EXPECT(!parseGenericSeed (
toBase58(calcAccountID(account2.first))));
BEAST_EXPECT(!parseGenericSeed (
toBase58(TokenType::TOKEN_ACCOUNT_PUBLIC, account2.first)));
toBase58(TokenType::AccountPublic, account2.first)));
BEAST_EXPECT(!parseGenericSeed (
toBase58(TokenType::TOKEN_ACCOUNT_SECRET, account2.second)));
toBase58(TokenType::AccountSecret, account2.second)));
}
void run() override

View File

@@ -69,7 +69,7 @@ class AccountCurrencies_test : public beast::unit_test::suite
{ // strict mode, using properly formatted bitcoin token
Json::Value params;
params[jss::account] = base58EncodeTokenBitcoin (
TOKEN_ACCOUNT_ID, alice.id().data(), alice.id().size());
TokenType::AccountID, alice.id().data(), alice.id().size());
params[jss::strict] = true;
auto const result = env.rpc ("json", "account_currencies",
boost::lexical_cast<std::string>(params)) [jss::result];

View File

@@ -308,7 +308,7 @@ public:
(keyType ? *keyType : "no key_type"));
auto const publicKey = parseBase58<PublicKey>(
TokenType::TOKEN_ACCOUNT_PUBLIC, strings.public_key);
TokenType::AccountPublic, strings.public_key);
BEAST_EXPECT(publicKey);
if (!keyType)

View File

@@ -112,7 +112,7 @@ class NoRippleCheck_test : public beast::unit_test::suite
// parsing as a seed to fail
Json::Value params;
params[jss::account] =
toBase58 (TokenType::TOKEN_NODE_PRIVATE, alice.sk());
toBase58 (TokenType::NodePrivate, alice.sk());
params[jss::role] = "user";
params[jss::ledger] = "current";
auto const result = env.rpc ("json", "noripple_check",

View File

@@ -58,7 +58,7 @@ class Peers_test : public beast::unit_test::suite
200,
env.timeKeeper().now() - 10s);
nodes.insert( std::make_pair(
toBase58(TokenType::TOKEN_NODE_PUBLIC, kp.first), name));
toBase58(TokenType::NodePublic, kp.first), name));
}
// make request, verify nodes we created match

View File

@@ -327,7 +327,7 @@ public:
return;
std::string const valPublicKey =
toBase58 (TokenType::TOKEN_NODE_PUBLIC,
toBase58 (TokenType::NodePublic,
derivePublicKey (KeyType::secp256k1,
generateSecretKey (KeyType::secp256k1, *parsedseed)));

View File

@@ -183,7 +183,7 @@ public:
using address_type = boost::asio::ip::address;
auto toStr = [](PublicKey const& publicKey) {
return toBase58(TokenType::TOKEN_NODE_PUBLIC, publicKey);
return toBase58(TokenType::NodePublic, publicKey);
};
// Publisher manifest/signing keys

View File

@@ -31,6 +31,7 @@
#include <test/protocol/STAmount_test.cpp>
#include <test/protocol/STObject_test.cpp>
#include <test/protocol/STTx_test.cpp>
#include <test/protocol/STValidation_test.cpp>
#include <test/protocol/TER_test.cpp>
#include <test/protocol/types_test.cpp>
#include <test/protocol/XRPAmount_test.cpp>
#include <test/protocol/XRPAmount_test.cpp>