diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/bitcoinconsensus.cpp | 2 | ||||
-rw-r--r-- | src/script/bitcoinconsensus.h | 1 | ||||
-rw-r--r-- | src/script/interpreter.cpp | 139 | ||||
-rw-r--r-- | src/script/interpreter.h | 16 | ||||
-rw-r--r-- | src/script/script.h | 2 | ||||
-rw-r--r-- | src/script/sigcache.cpp | 4 | ||||
-rw-r--r-- | src/script/sigcache.h | 4 | ||||
-rw-r--r-- | src/script/sign.cpp | 4 | ||||
-rw-r--r-- | src/script/standard.h | 3 |
9 files changed, 96 insertions, 79 deletions
diff --git a/src/script/bitcoinconsensus.cpp b/src/script/bitcoinconsensus.cpp index c8dd54a747..b0d5faaf77 100644 --- a/src/script/bitcoinconsensus.cpp +++ b/src/script/bitcoinconsensus.cpp @@ -78,7 +78,7 @@ int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned i // Regardless of the verification result, the tx did not error. set_error(err, bitcoinconsensus_ERR_OK); - return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, SignatureChecker(tx, nIn), NULL); + return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL); } catch (const std::exception&) { return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing } diff --git a/src/script/bitcoinconsensus.h b/src/script/bitcoinconsensus.h index 9d9c266435..0320577797 100644 --- a/src/script/bitcoinconsensus.h +++ b/src/script/bitcoinconsensus.h @@ -46,6 +46,7 @@ enum { bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0, bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts + bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance }; /// Returns 1 if the input nIn of the serialized transaction pointed to by diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index d0f75ab672..84a7432fdb 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -60,7 +60,7 @@ bool CastToBool(const valtype& vch) static inline void popstack(vector<valtype>& stack) { if (stack.empty()) - throw runtime_error("popstack() : stack empty"); + throw runtime_error("popstack(): stack empty"); stack.pop_back(); } @@ -93,76 +93,76 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { * in which case a single 0 byte is necessary and even required). * * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623 + * + * This function is consensus-critical since BIP66. */ -bool static IsDERSignature(const valtype &vchSig) { +bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) { + // Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash] + // * total-length: 1-byte length descriptor of everything that follows, + // excluding the sighash byte. + // * R-length: 1-byte length descriptor of the R value that follows. + // * R: arbitrary-length big-endian encoded R value. It must use the shortest + // possible encoding for a positive integers (which means no null bytes at + // the start, except a single one when the next byte has its highest bit set). + // * S-length: 1-byte length descriptor of the S value that follows. + // * S: arbitrary-length big-endian encoded S value. The same rules apply. + // * sighash: 1-byte value indicating what data is hashed (not part of the DER + // signature) - if (vchSig.size() < 9) { - // Non-canonical signature: too short - return false; - } - if (vchSig.size() > 73) { - // Non-canonical signature: too long - return false; - } - if (vchSig[0] != 0x30) { - // Non-canonical signature: wrong type - return false; - } - if (vchSig[1] != vchSig.size()-3) { - // Non-canonical signature: wrong length marker - return false; - } - unsigned int nLenR = vchSig[3]; - if (5 + nLenR >= vchSig.size()) { - // Non-canonical signature: S length misplaced - return false; - } - unsigned int nLenS = vchSig[5+nLenR]; - if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) { - // Non-canonical signature: R+S length mismatch - return false; - } + // Minimum and maximum size constraints. + if (sig.size() < 9) return false; + if (sig.size() > 73) return false; - const unsigned char *R = &vchSig[4]; - if (R[-2] != 0x02) { - // Non-canonical signature: R value type mismatch - return false; - } - if (nLenR == 0) { - // Non-canonical signature: R length is zero - return false; - } - if (R[0] & 0x80) { - // Non-canonical signature: R value negative - return false; - } - if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) { - // Non-canonical signature: R value excessively padded - return false; - } + // A signature is of type 0x30 (compound). + if (sig[0] != 0x30) return false; + + // Make sure the length covers the entire signature. + if (sig[1] != sig.size() - 3) return false; + + // Extract the length of the R element. + unsigned int lenR = sig[3]; + + // Make sure the length of the S element is still inside the signature. + if (5 + lenR >= sig.size()) return false; + + // Extract the length of the S element. + unsigned int lenS = sig[5 + lenR]; + + // Verify that the length of the signature matches the sum of the length + // of the elements. + if ((size_t)(lenR + lenS + 7) != sig.size()) return false; + + // Check whether the R element is an integer. + if (sig[2] != 0x02) return false; + + // Zero-length integers are not allowed for R. + if (lenR == 0) return false; + + // Negative numbers are not allowed for R. + if (sig[4] & 0x80) return false; + + // Null bytes at the start of R are not allowed, unless R would + // otherwise be interpreted as a negative number. + if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false; + + // Check whether the S element is an integer. + if (sig[lenR + 4] != 0x02) return false; + + // Zero-length integers are not allowed for S. + if (lenS == 0) return false; + + // Negative numbers are not allowed for S. + if (sig[lenR + 6] & 0x80) return false; + + // Null bytes at the start of S are not allowed, unless S would otherwise be + // interpreted as a negative number. + if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) return false; - const unsigned char *S = &vchSig[6+nLenR]; - if (S[-2] != 0x02) { - // Non-canonical signature: S value type mismatch - return false; - } - if (nLenS == 0) { - // Non-canonical signature: S length is zero - return false; - } - if (S[0] & 0x80) { - // Non-canonical signature: S value negative - return false; - } - if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) { - // Non-canonical signature: S value excessively padded - return false; - } return true; } bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) { - if (!IsDERSignature(vchSig)) { + if (!IsValidSignatureEncoding(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } unsigned int nLenR = vchSig[3]; @@ -189,7 +189,12 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) { } bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) { - if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) { + // 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; + } + if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsValidSignatureEncoding(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) { // serror is set @@ -1053,12 +1058,12 @@ uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsig return ss.GetHash(); } -bool SignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const +bool TransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { return pubkey.Verify(sighash, vchSig); } -bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const +bool TransactionSignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const { CPubKey pubkey(vchPubKey); if (!pubkey.IsValid()) @@ -1071,7 +1076,7 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec int nHashType = vchSig.back(); vchSig.pop_back(); - uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType); + uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, nHashType); if (!VerifySignature(vchSig, pubkey, sighash)) return false; diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 8bf379ed89..fc64438f68 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -7,6 +7,7 @@ #define BITCOIN_SCRIPT_INTERPRETER_H #include "script_error.h" +#include "primitives/transaction.h" #include <vector> #include <stdint.h> @@ -90,20 +91,29 @@ public: virtual ~BaseSignatureChecker() {} }; -class SignatureChecker : public BaseSignatureChecker +class TransactionSignatureChecker : public BaseSignatureChecker { private: - const CTransaction& txTo; + const CTransaction* txTo; unsigned int nIn; protected: virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; public: - SignatureChecker(const CTransaction& txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} + TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {} bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const; }; +class MutableTransactionSignatureChecker : public TransactionSignatureChecker +{ +private: + const CTransaction txTo; + +public: + MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {} +}; + bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL); diff --git a/src/script/script.h b/src/script/script.h index 78fd12cd29..8b36aa2f50 100644 --- a/src/script/script.h +++ b/src/script/script.h @@ -391,7 +391,7 @@ public: CScript& operator<<(opcodetype opcode) { if (opcode < 0 || opcode > 0xff) - throw std::runtime_error("CScript::operator<<() : invalid opcode"); + throw std::runtime_error("CScript::operator<<(): invalid opcode"); insert(end(), (unsigned char)opcode); return *this; } diff --git a/src/script/sigcache.cpp b/src/script/sigcache.cpp index 75ecdb563d..099b4ad0e3 100644 --- a/src/script/sigcache.cpp +++ b/src/script/sigcache.cpp @@ -74,14 +74,14 @@ public: } -bool CachingSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const +bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const { static CSignatureCache signatureCache; if (signatureCache.Get(sighash, vchSig, pubkey)) return true; - if (!SignatureChecker::VerifySignature(vchSig, pubkey, sighash)) + if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash)) return false; if (store) diff --git a/src/script/sigcache.h b/src/script/sigcache.h index 3bd11caff5..b299038daa 100644 --- a/src/script/sigcache.h +++ b/src/script/sigcache.h @@ -12,13 +12,13 @@ class CPubKey; -class CachingSignatureChecker : public SignatureChecker +class CachingTransactionSignatureChecker : public TransactionSignatureChecker { private: bool store; public: - CachingSignatureChecker(const CTransaction& txToIn, unsigned int nInIn, bool storeIn=true) : SignatureChecker(txToIn, nInIn), store(storeIn) {} + CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn), store(storeIn) {} bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const; }; diff --git a/src/script/sign.cpp b/src/script/sign.cpp index adddd4ec78..14119f7e2c 100644 --- a/src/script/sign.cpp +++ b/src/script/sign.cpp @@ -123,7 +123,7 @@ bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutabl } // Test solution - return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, SignatureChecker(txTo, nIn)); + return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&txTo, nIn)); } bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType) @@ -174,7 +174,7 @@ static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& if (sigs.count(pubkey)) continue; // Already got a sig for this pubkey - if (SignatureChecker(txTo, nIn).CheckSig(sig, pubkey, scriptPubKey)) + if (TransactionSignatureChecker(&txTo, nIn).CheckSig(sig, pubkey, scriptPubKey)) { sigs[pubkey] = sig; break; diff --git a/src/script/standard.h b/src/script/standard.h index ac80193773..a8b0acc981 100644 --- a/src/script/standard.h +++ b/src/script/standard.h @@ -25,7 +25,7 @@ public: CScriptID(const uint160& in) : uint160(in) {} }; -static const unsigned int MAX_OP_RETURN_RELAY = 40; //! bytes +static const unsigned int MAX_OP_RETURN_RELAY = 80; //! bytes extern unsigned nMaxDatacarrierBytes; /** @@ -45,6 +45,7 @@ static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH; * blocks and we must accept those blocks. */ static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS | + SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_STRICTENC | SCRIPT_VERIFY_MINIMALDATA | SCRIPT_VERIFY_NULLDUMMY | |