mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
Signature canonicalization and transaction mutation fixes
This commit is contained in:
committed by
Vinnie Falco
parent
93b44fcdc1
commit
ae649ec917
57
src/ripple/sslutil/api/ECDSACanonical.h
Normal file
57
src/ripple/sslutil/api/ECDSACanonical.h
Normal 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
|
||||
299
src/ripple/sslutil/impl/ECDSACanonical.cpp
Normal file
299
src/ripple/sslutil/impl/ECDSACanonical.cpp
Normal 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;
|
||||
|
||||
}
|
||||
@@ -22,5 +22,6 @@
|
||||
#include "ripple_sslutil.h"
|
||||
|
||||
#include "impl/CBigNum.cpp"
|
||||
#include "impl/ECDSACanonical.cpp"
|
||||
#include "impl/DHUtil.cpp"
|
||||
#include "impl/HashUtilities.cpp"
|
||||
|
||||
@@ -38,5 +38,6 @@ using namespace beast;
|
||||
#include "api/CBigNum.h"
|
||||
#include "api/DHUtil.h"
|
||||
#include "api/HashUtilities.h"
|
||||
#include "api/ECDSACanonical.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 (...)
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 (...)
|
||||
{
|
||||
|
||||
@@ -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.";
|
||||
|
||||
|
||||
@@ -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.";
|
||||
|
||||
|
||||
@@ -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 ";
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.";
|
||||
|
||||
Reference in New Issue
Block a user