libconsensus: Add input validation of flags

Makes it an error to use flags that have not been defined
on the libconsensus API.

There has been some confusion as to what pass to libconsensus, and
(combined with mention in the release notes) this should clear it up.

Using undocumented flags is a risk because their meaning,
and what combinations are allowed, changes from release to release.
E.g. it is no longer possible to pass (CLEANSTACK | P2SH) without
running into an assertion after the segwit changes.
This commit is contained in:
Wladimir J. van der Laan 2016-10-20 08:30:03 +02:00
parent c587577356
commit 5ca8ef299a
3 changed files with 21 additions and 5 deletions

View File

@ -69,10 +69,19 @@ struct ECCryptoClosure
ECCryptoClosure instance_of_eccryptoclosure; ECCryptoClosure instance_of_eccryptoclosure;
} }
/** Check that all specified flags are part of the libconsensus interface. */
static bool verify_flags(unsigned int flags)
{
return (flags & ~(bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL)) == 0;
}
static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount, static int verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen, CAmount amount,
const unsigned char *txTo , unsigned int txToLen, const unsigned char *txTo , unsigned int txToLen,
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err) unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
{ {
if (!verify_flags(flags)) {
return bitcoinconsensus_ERR_INVALID_FLAGS;
}
try { try {
TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen); TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen);
CTransaction tx; CTransaction tx;

View File

@ -42,6 +42,7 @@ typedef enum bitcoinconsensus_error_t
bitcoinconsensus_ERR_TX_SIZE_MISMATCH, bitcoinconsensus_ERR_TX_SIZE_MISMATCH,
bitcoinconsensus_ERR_TX_DESERIALIZE, bitcoinconsensus_ERR_TX_DESERIALIZE,
bitcoinconsensus_ERR_AMOUNT_REQUIRED, bitcoinconsensus_ERR_AMOUNT_REQUIRED,
bitcoinconsensus_ERR_INVALID_FLAGS,
} bitcoinconsensus_error; } bitcoinconsensus_error;
/** Script verification flags */ /** Script verification flags */
@ -54,6 +55,9 @@ enum
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65) bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9), // enable CHECKLOCKTIMEVERIFY (BIP65)
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), // enable CHECKSEQUENCEVERIFY (BIP112) bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10), // enable CHECKSEQUENCEVERIFY (BIP112)
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS = (1U << 11), // enable WITNESS (BIP141) bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS = (1U << 11), // enable WITNESS (BIP141)
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL = bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG |
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NULLDUMMY | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKLOCKTIMEVERIFY |
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_CHECKSEQUENCEVERIFY | bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS
}; };
/// Returns 1 if the input nIn of the serialized transaction pointed to by /// Returns 1 if the input nIn of the serialized transaction pointed to by

View File

@ -173,11 +173,14 @@ void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, const CScript
#if defined(HAVE_CONSENSUS_LIB) #if defined(HAVE_CONSENSUS_LIB)
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
stream << tx2; stream << tx2;
if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) { int libconsensus_flags = flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_ALL;
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message); if (libconsensus_flags == flags) {
} else { if (flags & bitcoinconsensus_SCRIPT_FLAGS_VERIFY_WITNESS) {
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect, message); BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), txCredit.vout[0].nValue, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, flags, NULL) == expect,message); } else {
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script_with_amount(begin_ptr(scriptPubKey), scriptPubKey.size(), 0, (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect, message);
BOOST_CHECK_MESSAGE(bitcoinconsensus_verify_script(begin_ptr(scriptPubKey), scriptPubKey.size(), (const unsigned char*)&stream[0], stream.size(), 0, libconsensus_flags, NULL) == expect,message);
}
} }
#endif #endif
} }