Browse Source

Add constant scriptCode policy in non-segwit scripts

This disables OP_CODESEPARATOR in non-segwit scripts (even in an unexecuted branch), and makes a positive FindAndDelete result invalid. This ensures that the scriptCode serialized in SignatureHash() is always the same as the script passing to the EvalScript.

Github-Pull: #11423
Rebased-From: 9dabfe49c066301ef75bcfcb089fd308366127c4
0.16
Johnson Lau 7 years ago committed by MarcoFalke
parent
commit
d353dd121b
  1. 3
      src/policy/policy.h
  2. 15
      src/script/interpreter.cpp
  3. 4
      src/script/interpreter.h
  4. 4
      src/script/script_error.cpp
  5. 4
      src/script/script_error.h
  6. 2
      src/test/script_tests.cpp

3
src/policy/policy.h

@ -63,7 +63,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_LOW_S |
SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_WITNESS |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM | SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE; SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
SCRIPT_VERIFY_CONST_SCRIPTCODE;
/** For convenience, standard but not mandatory verify flags. */ /** For convenience, standard but not mandatory verify flags. */
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS; static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;

15
src/script/interpreter.cpp

@ -306,6 +306,10 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
opcode == OP_RSHIFT) opcode == OP_RSHIFT)
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes. return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
// With SCRIPT_VERIFY_CONST_SCRIPTCODE, OP_CODESEPARATOR in non-segwit script is rejected even in an unexecuted branch
if (opcode == OP_CODESEPARATOR && sigversion == SIGVERSION_BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
return set_error(serror, SCRIPT_ERR_OP_CODESEPARATOR);
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
return set_error(serror, SCRIPT_ERR_MINIMALDATA); return set_error(serror, SCRIPT_ERR_MINIMALDATA);
@ -869,6 +873,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
case OP_CODESEPARATOR: case OP_CODESEPARATOR:
{ {
// If SCRIPT_VERIFY_CONST_SCRIPTCODE flag is set, use of OP_CODESEPARATOR is rejected in pre-segwit
// script, even in an unexecuted branch (this is checked above the opcode case statement).
// Hash starts after the code separator // Hash starts after the code separator
pbegincodehash = pc; pbegincodehash = pc;
} }
@ -889,7 +896,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
// Drop the signature in pre-segwit scripts but not segwit scripts // Drop the signature in pre-segwit scripts but not segwit scripts
if (sigversion == SIGVERSION_BASE) { if (sigversion == SIGVERSION_BASE) {
scriptCode.FindAndDelete(CScript(vchSig)); int found = scriptCode.FindAndDelete(CScript(vchSig));
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
} }
if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) { if (!CheckSignatureEncoding(vchSig, flags, serror) || !CheckPubKeyEncoding(vchPubKey, flags, sigversion, serror)) {
@ -953,7 +962,9 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
{ {
valtype& vchSig = stacktop(-isig-k); valtype& vchSig = stacktop(-isig-k);
if (sigversion == SIGVERSION_BASE) { if (sigversion == SIGVERSION_BASE) {
scriptCode.FindAndDelete(CScript(vchSig)); int found = scriptCode.FindAndDelete(CScript(vchSig));
if (found > 0 && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
return set_error(serror, SCRIPT_ERR_SIG_FINDANDDELETE);
} }
} }

4
src/script/interpreter.h

@ -111,6 +111,10 @@ enum
// Public keys in segregated witness scripts must be compressed // Public keys in segregated witness scripts must be compressed
// //
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15), SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
//
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
}; };
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror); bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);

4
src/script/script_error.cpp

@ -89,6 +89,10 @@ const char* ScriptErrorString(const ScriptError serror)
return "Witness provided for non-witness script"; return "Witness provided for non-witness script";
case SCRIPT_ERR_WITNESS_PUBKEYTYPE: case SCRIPT_ERR_WITNESS_PUBKEYTYPE:
return "Using non-compressed keys in segwit"; return "Using non-compressed keys in segwit";
case SCRIPT_ERR_OP_CODESEPARATOR:
return "Using OP_CODESEPARATOR in non-witness script";
case SCRIPT_ERR_SIG_FINDANDDELETE:
return "Signature is found in scriptCode";
case SCRIPT_ERR_UNKNOWN_ERROR: case SCRIPT_ERR_UNKNOWN_ERROR:
case SCRIPT_ERR_ERROR_COUNT: case SCRIPT_ERR_ERROR_COUNT:
default: break; default: break;

4
src/script/script_error.h

@ -64,6 +64,10 @@ typedef enum ScriptError_t
SCRIPT_ERR_WITNESS_UNEXPECTED, SCRIPT_ERR_WITNESS_UNEXPECTED,
SCRIPT_ERR_WITNESS_PUBKEYTYPE, SCRIPT_ERR_WITNESS_PUBKEYTYPE,
/* Constant scriptCode */
SCRIPT_ERR_OP_CODESEPARATOR,
SCRIPT_ERR_SIG_FINDANDDELETE,
SCRIPT_ERR_ERROR_COUNT SCRIPT_ERR_ERROR_COUNT
} ScriptError; } ScriptError;

2
src/test/script_tests.cpp

@ -97,6 +97,8 @@ static ScriptErrorDesc script_errors[]={
{SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"}, {SCRIPT_ERR_WITNESS_MALLEATED_P2SH, "WITNESS_MALLEATED_P2SH"},
{SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"}, {SCRIPT_ERR_WITNESS_UNEXPECTED, "WITNESS_UNEXPECTED"},
{SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"}, {SCRIPT_ERR_WITNESS_PUBKEYTYPE, "WITNESS_PUBKEYTYPE"},
{SCRIPT_ERR_OP_CODESEPARATOR, "OP_CODESEPARATOR"},
{SCRIPT_ERR_SIG_FINDANDDELETE, "SIG_FINDANDDELETE"},
}; };
const char *FormatScriptError(ScriptError_t err) const char *FormatScriptError(ScriptError_t err)

Loading…
Cancel
Save