Signature canonicalization and transaction mutation fixes

This commit is contained in:
David Schwartz
2014-02-18 18:37:55 -08:00
committed by Vinnie Falco
parent 93b44fcdc1
commit ae649ec917
17 changed files with 412 additions and 32 deletions

View File

@@ -0,0 +1,57 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
#ifndef RIPPLE_SSLUTIL_ECDSACANONICAL_H_INCLUDED
#define RIPPLE_SSLUTIL_ECDSACANONICAL_H_INCLUDED
namespace ripple {
enum class ECDSA
{
not_strict = 0,
strict
};
/** Checks whether a secp256k1 ECDSA signature is canonical.
Return value is true if the signature is canonical.
If mustBeStrict is specified, the signature must be
strictly canonical (one and only one valid form).
The return value for something that is not an ECDSA
signature is unspecified. (But the function will not crash.)
*/
bool isCanonicalECDSASig (void const* signature, size_t sigLen, ECDSA mustBeStrict);
inline bool isCanonicalECDSASig (Blob const& signature, ECDSA mustBeStrict)
{
return signature.empty() ? false : isCanonicalECDSASig (&signature[0], signature.size(), mustBeStrict);
}
/** Converts a canonical secp256k1 ECDSA signature to a
fully-canonical one. Returns true if the original signature
was already fully-canonical. The behavior if something
that is not a canonical secp256k1 ECDSA signature is
passed is unspecified. The signature buffer must be large
enough to accommodate the largest valid fully-canonical
secp256k1 ECDSA signature (72 bytes).
*/
bool makeCanonicalECDSASig (void *signature, size_t& sigLen);
}
#endif

View File

@@ -0,0 +1,299 @@
//------------------------------------------------------------------------------
/*
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.
*/
//==============================================================================
namespace ripple {
namespace detail {
// A simple wrapper for a BIGNUM to make it
// easier to allocate, construct, and free them
struct BigNum
{
BIGNUM* num;
BigNum (BigNum const&) = delete;
BigNum& operator=(BigNum const&) = delete;
BigNum (const char *hex)
{
num = BN_new ();
BN_hex2bn (&num, hex);
}
BigNum ()
{
num = BN_new ();
}
BigNum (unsigned char const* ptr, size_t len)
{
num = BN_new ();
BN_bin2bn (ptr, len, num);
}
~BigNum ()
{
BN_free (num);
}
operator BIGNUM* ()
{
return num;
}
};
// The SECp256k1 modulus
static BigNum modulus ("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141");
}
bool isCanonicalECDSASig (void const* vSig, size_t sigLen, ECDSA strict_param)
{
// Make sure signature is canonical
// To protect against signature morphing attacks
// See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
// and https://github.com/sipa/bitcoin/commit/58bc86e37fda1aec270bccb3df6c20fbd2a6591c
// Signature should be:
// <30> <len> [ <02> <lenR> <R> ] [ <02> <lenS> <S> ]
const bool strict = strict_param == ECDSA::strict;
unsigned char const* sig = reinterpret_cast<unsigned char const*> (vSig);
if ((sigLen < 10) || (sigLen > 74))
return false;
if ((sig[0] != 0x30) || (sig[1] != (sigLen - 2)))
return false;
// Find R and check its length
int rPos = 4, rLen = sig[3];
if ((rLen < 2) || ((rLen + 6) > sigLen))
return false;
// Find S and check its length
int sPos = rLen + 6, sLen = sig [rLen + 5];
if ((sLen < 2) || ((rLen + sLen + 6) != sigLen))
return false;
if ((sig[rPos - 2] != 0x02) || (sig[sPos - 2] != 0x02))
return false; // R or S have wrong type
if ((sig[rPos] & 0x80) != 0)
return false; // R is negative
if ((sig[rPos] == 0) && ((sig[rPos + 1] & 0x80) == 0))
return false; // R is padded
if ((sig[sPos] & 0x80) != 0)
return false; // S is negative
if ((sig[sPos] == 0) && ((sig[sPos + 1] & 0x80) == 0))
return false; // S is padded
detail::BigNum bnR (&sig[rPos], rLen);
detail::BigNum bnS (&sig[sPos], sLen);
if ((BN_cmp (bnR, detail::modulus) != -1) || (BN_cmp (bnS, detail::modulus) != -1))
return false; // R or S greater than modulus
if (!strict)
return true;
detail::BigNum mS;
BN_sub (mS, detail::modulus, bnS);
return BN_cmp (bnS, mS) != 1;
}
// Returns true if original signature was alread canonical
bool makeCanonicalECDSASig (void* vSig, size_t& sigLen)
{
// Signature is (r,s) where 0 < s < g
// If (g-s)<g, replace signature with (r,g-s)
unsigned char * sig = reinterpret_cast<unsigned char *> (vSig);
bool ret = false;
// Find internals
int rLen = sig[3];
int sPos = rLen + 6, sLen = sig[rLen + 5];
detail::BigNum origS, newS;
BN_bin2bn (&sig[sPos], sLen, origS);
BN_sub (newS, detail::modulus, origS);
if (BN_cmp (origS, newS) == 1)
{ // original signature is not fully canonical
unsigned char newSbuf [64];
int newSlen = BN_bn2bin (newS, newSbuf);
if ((newSbuf[0] & 0x80) == 0)
{ // no extra padding byte is needed
sig[1] = sig[1] - sLen + newSlen;
sig[sPos - 1] = newSlen;
memcpy (&sig[sPos], newSbuf, newSlen);
}
else
{ // an extra padding byte is needed
sig[1] = sig[1] - sLen + newSlen + 1;
sig[sPos - 1] = newSlen + 1;
sig[sPos] = 0;
memcpy (&sig[sPos + 1], newSbuf, newSlen);
}
sigLen = sig[1] + 2;
}
else
ret = true;
return ret;
}
template <class FwdIter, class Container>
void hex_to_binary (FwdIter first, FwdIter last, Container& out)
{
struct Table
{
int val[256];
Table ()
{
std::fill (val, val+256, 0);
for (int i = 0; i < 10; ++i)
val ['0'+i] = i;
for (int i = 0; i < 6; ++i)
{
val ['A'+i] = 10 + i;
val ['a'+i] = 10 + i;
}
}
int operator[] (int i)
{
return val[i];
}
};
static Table lut;
out.reserve (std::distance (first, last) / 2);
while (first != last)
{
auto const hi (lut[(*first++)]);
auto const lo (lut[(*first++)]);
out.push_back ((hi*16)+lo);
}
}
class ECDSACanonicalTests : public UnitTest
{
public:
ECDSACanonicalTests () : UnitTest ("ECDSACanonical", "ripple")
{
}
bool isCanonical (std::string const& hex)
{
Blob j;
hex_to_binary (hex.begin(), hex.end(), j);
return isCanonicalECDSASig (&j[0], j.size(), ECDSA::not_strict);
}
void runTest ()
{
beginTestCase ("canonicalSignatures");
expect (isCanonical("304402203932c892e2e550f3af8ee4ce9c215a87f9bb"
"831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f"
"53189e5af33cdda8d77a5209aec03978fa001"), "canonical signature");
expect (isCanonical("30450220076045be6f9eca28ff1ec606b833d0b87e70b"
"2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688"
"eca1d2ba7f6b180620eaa03488e6585db6ba01"), "canonical signature");
expect (isCanonical("3046022100876045be6f9eca28ff1ec606b833d0b87e7"
"0b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c"
"2eca1d2ba7f6b180620eaa03488e6585db6ba"), "canonical signature");
expect (!isCanonical("3005" "0201FF" "0200"), "tooshort");
expect (!isCanonical("3047"
"0221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"toolong");
expect (!isCanonical("3144"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"type");
expect (!isCanonical("3045"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"totallength");
expect (!isCanonical(
"301F" "01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1"),
"Slenoob");
expect (!isCanonical("3045"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed00"),
"R+S");
expect (!isCanonical("3044"
"01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"Rtype");
expect (!isCanonical("3024" "0200"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"Rlen=0");
expect (!isCanonical("3044"
"02208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"R<0");
expect (!isCanonical("3045"
"0221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"02202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"Rpadded");
expect (!isCanonical("3044"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105012"
"02d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"Stype");
expect (!isCanonical("3024"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"0200"),
"Slen=0");
expect (!isCanonical("3044"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"0220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"S<0");
expect (!isCanonical("3045"
"02205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105"
"0221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed"),
"Spadded");
}
};
static ECDSACanonicalTests ECDSACTests;
}

View File

@@ -22,5 +22,6 @@
#include "ripple_sslutil.h"
#include "impl/CBigNum.cpp"
#include "impl/ECDSACanonical.cpp"
#include "impl/DHUtil.cpp"
#include "impl/HashUtilities.cpp"

View File

@@ -38,5 +38,6 @@ using namespace beast;
#include "api/CBigNum.h"
#include "api/DHUtil.h"
#include "api/HashUtilities.h"
#include "api/ECDSACanonical.h"
#endif

View File

@@ -61,7 +61,7 @@ uint256 LedgerProposal::getSigningHash () const
bool LedgerProposal::checkSign (const std::string& signature, uint256 const& signingHash)
{
return mPublicKey.verifyNodePublic (signingHash, signature);
return mPublicKey.verifyNodePublic (signingHash, signature, ECDSA::not_strict);
}
bool LedgerProposal::changePosition (uint256 const& newPosition, uint32 closeTime)

View File

@@ -92,8 +92,11 @@ bool SerializedValidation::isValid (uint256 const& signingHash) const
{
try
{
const ECDSA fullyCanonical = getFlags () & vfFullyCanonicalSig ?
ECDSA::strict : ECDSA::not_strict;
RippleAddress raPublicKey = RippleAddress::createNodePublic (getFieldVL (sfSigningPubKey));
return raPublicKey.isValid () && raPublicKey.verifyNodePublic (signingHash, getFieldVL (sfSignature));
return raPublicKey.isValid () &&
raPublicKey.verifyNodePublic (signingHash, getFieldVL (sfSignature), fullyCanonical);
}
catch (...)
{

View File

@@ -20,6 +20,9 @@
#ifndef RIPPLE_SERIALIZEDVALIDATION_H
#define RIPPLE_SERIALIZEDVALIDATION_H
// Validation flags
const uint32 vfFullyCanonicalSig = 0x80000000; // signature is fully canonical
class SerializedValidation
: public STObject
, public CountedObject <SerializedValidation>

View File

@@ -217,7 +217,9 @@ bool SerializedTransaction::checkSign (const RippleAddress& naAccountPublic) con
{
try
{
return naAccountPublic.accountPublicVerify (getSigningHash (), getFieldVL (sfTxnSignature));
const ECDSA fullyCanonical = (getFlags() & tfFullyCanonicalSig) ?
ECDSA::strict : ECDSA::not_strict;
return naAccountPublic.accountPublicVerify (getSigningHash (), getFieldVL (sfTxnSignature), fullyCanonical);
}
catch (...)
{

View File

@@ -29,7 +29,7 @@ TER OfferCancelTransactor::doApply ()
const uint32 uTxFlags = mTxn.getFlags ();
if (uTxFlags)
if (uTxFlags & tfUniversalMask)
{
WriteLog (lsINFO, OfferCancelTransactor) << "OfferCancel: Malformed transaction: Invalid flags set.";

View File

@@ -39,7 +39,7 @@ TER RegularKeySetTransactor::doApply ()
const uint32 uTxFlags = mTxn.getFlags ();
if (uTxFlags)
if (uTxFlags & tfUniversalMask)
{
WriteLog (lsINFO, RegularKeySetTransactor) << "RegularKeySet: Malformed transaction: Invalid flags set.";

View File

@@ -31,7 +31,7 @@ TER WalletAddTransactor::doApply ()
const uint32 uTxFlags = mTxn.getFlags ();
if (uTxFlags)
if (uTxFlags & tfUniversalMask)
{
WriteLog (lsINFO, WalletAddTransactor) << "WalletAdd: Malformed transaction: Invalid flags set.";
@@ -39,7 +39,8 @@ TER WalletAddTransactor::doApply ()
}
// FIXME: This should be moved to the transaction's signature check logic and cached
if (!naMasterPubKey.accountPublicVerify (Serializer::getSHA512Half (uAuthKeyID.begin (), uAuthKeyID.size ()), vucSignature))
if (!naMasterPubKey.accountPublicVerify (
Serializer::getSHA512Half (uAuthKeyID.begin (), uAuthKeyID.size ()), vucSignature, ECDSA::not_strict))
{
Log::out() << "WalletAdd: unauthorized: bad signature ";

View File

@@ -271,16 +271,16 @@ public:
bool Sign (uint256 const& hash, Blob& vchSig)
{
unsigned char pchSig[10000];
unsigned int nSize = 0;
vchSig.clear ();
unsigned char pchSig[128];
unsigned int nSize = sizeof(pchSig)/sizeof(pchSig[0]) - 1;
if (!ECDSA_sign (0, (unsigned char*)hash.begin (), hash.size (), pchSig, &nSize, pkey))
return false;
vchSig.resize (nSize);
memcpy (&vchSig[0], pchSig, nSize);
size_t len = nSize;
makeCanonicalECDSASig (pchSig, len);
vchSig.resize (len);
memcpy (&vchSig[0], pchSig, len);
return true;
}

View File

@@ -161,12 +161,14 @@ void RippleAddress::setNodePublic (Blob const& vPublic)
SetData (VER_NODE_PUBLIC, vPublic);
}
bool RippleAddress::verifyNodePublic (uint256 const& hash, Blob const& vchSig) const
bool RippleAddress::verifyNodePublic (uint256 const& hash, Blob const& vchSig, ECDSA fullyCanonical) const
{
CKey pubkey = CKey ();
bool bVerified;
if (!pubkey.SetPubKey (getNodePublic ()))
bVerified = isCanonicalECDSASig (vchSig, fullyCanonical);
if (bVerified && !pubkey.SetPubKey (getNodePublic ()))
{
// Failed to set public key.
bVerified = false;
@@ -179,11 +181,11 @@ bool RippleAddress::verifyNodePublic (uint256 const& hash, Blob const& vchSig) c
return bVerified;
}
bool RippleAddress::verifyNodePublic (uint256 const& hash, const std::string& strSig) const
bool RippleAddress::verifyNodePublic (uint256 const& hash, const std::string& strSig, ECDSA fullyCanonical) const
{
Blob vchSig (strSig.begin (), strSig.end ());
return verifyNodePublic (hash, vchSig);
return verifyNodePublic (hash, vchSig, fullyCanonical);
}
//
@@ -442,12 +444,13 @@ void RippleAddress::setAccountPublic (const RippleAddress& generator, int seq)
setAccountPublic (pubkey.GetPubKey ());
}
bool RippleAddress::accountPublicVerify (uint256 const& uHash, Blob const& vucSig) const
bool RippleAddress::accountPublicVerify (uint256 const& uHash, Blob const& vucSig, ECDSA fullyCanonical) const
{
CKey ckPublic;
bool bVerified;
if (!ckPublic.SetPubKey (getAccountPublic ()))
bool bVerified = isCanonicalECDSASig (vucSig, fullyCanonical);
if (bVerified && !ckPublic.SetPubKey (getAccountPublic ()))
{
// Bad private key.
WriteLog (lsWARNING, RippleAddress) << "accountPublicVerify: Bad private key.";
@@ -919,7 +922,7 @@ public:
Blob vucTextSig;
naNodePrivate.signNodePrivate (uHash, vucTextSig);
expect (naNodePublic.verifyNodePublic (uHash, vucTextSig), "Verify failed.");
expect (naNodePublic.verifyNodePublic (uHash, vucTextSig, ECDSA::strict), "Verify failed.");
// Construct a public generator from the seed.
RippleAddress naGenerator = RippleAddress::createGeneratorPublic (naSeed);
@@ -944,12 +947,14 @@ public:
// Check account signing.
expect (naAccountPrivate0.accountPrivateSign (uHash, vucTextSig), "Signing failed.");
expect (naAccountPublic0.accountPublicVerify (uHash, vucTextSig), "Verify failed.");
expect (!naAccountPublic1.accountPublicVerify (uHash, vucTextSig), "Anti-verify failed.");
expect (naAccountPublic0.accountPublicVerify (uHash, vucTextSig, ECDSA::strict), "Verify failed.");
expect (!naAccountPublic1.accountPublicVerify (uHash, vucTextSig, ECDSA::not_strict), "Anti-verify failed.");
expect (!naAccountPublic1.accountPublicVerify (uHash, vucTextSig, ECDSA::strict), "Anti-verify failed.");
expect (naAccountPrivate1.accountPrivateSign (uHash, vucTextSig), "Signing failed.");
expect (naAccountPublic1.accountPublicVerify (uHash, vucTextSig), "Verify failed.");
expect (!naAccountPublic0.accountPublicVerify (uHash, vucTextSig), "Anti-verify failed.");
expect (naAccountPublic1.accountPublicVerify (uHash, vucTextSig, ECDSA::strict), "Verify failed.");
expect (!naAccountPublic0.accountPublicVerify (uHash, vucTextSig, ECDSA::not_strict), "Anti-verify failed.");
expect (!naAccountPublic0.accountPublicVerify (uHash, vucTextSig, ECDSA::strict), "Anti-verify failed.");
// Check account encryption.
Blob vucTextCipher

View File

@@ -20,6 +20,8 @@
#ifndef RIPPLE_RIPPLEADDRESS_H
#define RIPPLE_RIPPLEADDRESS_H
#include "../ripple/sslutil/api/ECDSACanonical.h"
//
// Used to hold addresses and parse and produce human formats.
//
@@ -65,8 +67,8 @@ public:
bool setNodePublic (const std::string& strPublic);
void setNodePublic (Blob const& vPublic);
bool verifyNodePublic (uint256 const& hash, Blob const& vchSig) const;
bool verifyNodePublic (uint256 const& hash, const std::string& strSig) const;
bool verifyNodePublic (uint256 const& hash, Blob const& vchSig, ECDSA mustBeFullyCanonical) const;
bool verifyNodePublic (uint256 const& hash, const std::string& strSig, ECDSA mustBeFullyCanonical) const;
static RippleAddress createNodePublic (const RippleAddress& naSeed);
static RippleAddress createNodePublic (Blob const& vPublic);
@@ -127,7 +129,7 @@ public:
void setAccountPublic (Blob const& vPublic);
void setAccountPublic (const RippleAddress& generator, int seq);
bool accountPublicVerify (uint256 const& uHash, Blob const& vucSig) const;
bool accountPublicVerify (uint256 const& uHash, Blob const& vucSig, ECDSA mustBeFullyCanonical) const;
static RippleAddress createAccountPublic (Blob const& vPublic)
{

View File

@@ -38,6 +38,11 @@ public:
};
// VFALCO TODO Move all flags into this container after some study.
// Universal Transaction flags:
const uint32 tfFullyCanonicalSig = 0x80000000;
const uint32 tfUniversal = tfFullyCanonicalSig;
const uint32 tfUniversalMask = ~ tfUniversal;
// AccountSet flags:
// VFALCO TODO Javadoc comment every one of these constants
//const uint32 TxFlag::requireDestTag = 0x00010000;
@@ -62,18 +67,18 @@ const uint32 tfPassive = 0x00010000;
const uint32 tfImmediateOrCancel = 0x00020000;
const uint32 tfFillOrKill = 0x00040000;
const uint32 tfSell = 0x00080000;
const uint32 tfOfferCreateMask = ~ (tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
const uint32 tfOfferCreateMask = ~ (tfUniversal | tfPassive | tfImmediateOrCancel | tfFillOrKill | tfSell);
// Payment flags:
const uint32 tfNoRippleDirect = 0x00010000;
const uint32 tfPartialPayment = 0x00020000;
const uint32 tfLimitQuality = 0x00040000;
const uint32 tfPaymentMask = ~ (tfPartialPayment | tfLimitQuality | tfNoRippleDirect);
const uint32 tfPaymentMask = ~ (tfUniversal | tfPartialPayment | tfLimitQuality | tfNoRippleDirect);
// TrustSet flags:
const uint32 tfSetfAuth = 0x00010000;
const uint32 tfSetNoRipple = 0x00020000;
const uint32 tfClearNoRipple = 0x00040000;
const uint32 tfTrustSetMask = ~ (tfSetfAuth | tfSetNoRipple | tfClearNoRipple);
const uint32 tfTrustSetMask = ~ (tfUniversal | tfSetfAuth | tfSetNoRipple | tfClearNoRipple);
#endif

View File

@@ -22,6 +22,7 @@
#include "../ripple_basics/ripple_basics.h"
#include "../ripple/json/ripple_json.h"
#include "../ripple/sslutil/api/ECDSACanonical.h"
struct bignum_st;
typedef struct bignum_st BIGNUM;

View File

@@ -1397,7 +1397,7 @@ private:
{
m_journal.info << "Hello: Disconnect: Bad node public key.";
}
else if (!m_nodePublicKey.verifyNodePublic (m_secureCookie, packet.nodeproof ()))
else if (!m_nodePublicKey.verifyNodePublic (m_secureCookie, packet.nodeproof (), ECDSA::not_strict))
{
// Unable to verify they have private key for claimed public key.
m_journal.info << "Hello: Disconnect: Failed to verify session.";