diff --git a/src/script/sigencoding.h b/src/script/sigencoding.h --- a/src/script/sigencoding.h +++ b/src/script/sigencoding.h @@ -27,6 +27,14 @@ } // namespace +/** + * Check that the signature provided on some data is properly encoded. + * Signatures passed to OP_CHECKDATASIG and its verify variant must be checked + * using this function. + */ +bool CheckDataSignatureEncoding(const valtype &vchSig, uint32_t flags, + ScriptError *serror); + /** * Check that the signature provided to authentify a transaction is properly * encoded. Signatures passed to OP_CHECKSIG, OP_CHECKMULTISIG and their verify diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp --- a/src/script/sigencoding.cpp +++ b/src/script/sigencoding.cpp @@ -168,6 +168,18 @@ return true; } +bool CheckDataSignatureEncoding(const valtype &vchSig, uint32_t flags, + ScriptError *serror) { + // Empty signature. Not strictly DER encoded, but allowed to provide a + // compact way to provide an invalid signature for use with CHECK(MULTI)SIG + if (vchSig.size() == 0) { + return true; + } + + return CheckRawSignatureEncoding( + vchSig | boost::adaptors::sliced(0, vchSig.size()), flags, serror); +} + bool CheckTransactionSignatureEncoding(const valtype &vchSig, uint32_t flags, ScriptError *serror) { // Empty signature. Not strictly DER encoded, but allowed to provide a diff --git a/src/test/sigencoding_tests.cpp b/src/test/sigencoding_tests.cpp --- a/src/test/sigencoding_tests.cpp +++ b/src/test/sigencoding_tests.cpp @@ -19,8 +19,11 @@ static void CheckSignatureErrorForAllSigHashType(const valtype &vchSig, uint32_t flags, const ScriptError expected_error) { + ScriptError err = SCRIPT_ERR_OK; + BOOST_CHECK(!CheckDataSignatureEncoding(vchSig, flags, &err)); + BOOST_CHECK_EQUAL(err, expected_error); + for (int i = 0; i <= 0xff; i++) { - ScriptError err = SCRIPT_ERR_OK; valtype sig = SignatureWithHashType(vchSig, SigHashType(i)); BOOST_CHECK(!CheckTransactionSignatureEncoding(sig, flags, &err)); BOOST_CHECK_EQUAL(err, expected_error); @@ -29,6 +32,9 @@ static void CheckSignatureEncodingWithSigHashType(const valtype &vchSig, uint32_t flags) { + ScriptError err = SCRIPT_ERR_OK; + BOOST_CHECK(CheckDataSignatureEncoding(vchSig, flags, &err)); + const bool hasForkId = (flags & SCRIPT_ENABLE_SIGHASH_FORKID) != 0; const bool hasStrictEnc = (flags & SCRIPT_VERIFY_STRICTENC) != 0; @@ -43,8 +49,6 @@ } for (const SigHashType baseSigHash : baseSigHashes) { - ScriptError err = SCRIPT_ERR_OK; - // Check the signature with the proper forkid flag. SigHashType sigHash = baseSigHash.withForkId(hasForkId); valtype validSig = SignatureWithHashType(vchSig, sigHash); @@ -172,6 +176,7 @@ ScriptError err = SCRIPT_ERR_OK; // Empty sig is always valid. + BOOST_CHECK(CheckDataSignatureEncoding({}, flags, &err)); BOOST_CHECK(CheckTransactionSignatureEncoding({}, flags, &err)); // Signature are valid as long as the forkid flag is correct.