diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp index 023f1d1e5..22f92c9ee 100644 --- a/src/script/sigencoding.cpp +++ b/src/script/sigencoding.cpp @@ -1,177 +1,243 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2016 The Bitcoin Core developers // Copyright (c) 2017-2018 The Bitcoin developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "sigencoding.h" #include "pubkey.h" #include "script_flags.h" #include /** * A canonical signature exists of: <30> <02> <02> , where R and S are not negative (their first byte has its * highest bit not set), and not excessively padded (do not start with a 0 byte, * unless an otherwise negative number follows, 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. */ static bool IsValidSignatureEncoding(const valtype &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) // Minimum and maximum size constraints. - if (sig.size() < 9) return false; - if (sig.size() > 73) return false; + if (sig.size() < 9 || sig.size() > 73) { + return false; + } + + // + // Check that the signature is a coumpound structure of proper size. + // // A signature is of type 0x30 (compound). - if (sig[0] != 0x30) return false; + 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]; + // Remove: + // * 1 byte for the coupound type. + // * 1 byte for the length of the signature. + // * 1 byte for the sighash type. + if (sig[1] != sig.size() - 3) { + return false; + } - // 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 that R is an positive integer of sensible size. + // // Check whether the R element is an integer. - if (sig[2] != 0x02) return false; + if (sig[2] != 0x02) { + return false; + } + + // Extract the length of the R element. + const uint32_t lenR = sig[3]; // Zero-length integers are not allowed for R. - if (lenR == 0) return false; + if (lenR == 0) { + return false; + } // Negative numbers are not allowed for R. - if (sig[4] & 0x80) return false; + if (sig[4] & 0x80) { + return false; + } + + // Make sure the length of the R element is consistent with the signature + // size. + // Remove: + // * 1 byte for the coumpound type. + // * 1 byte for the length of the signature. + // * 2 bytes for the integer type of R and S. + // * 2 bytes for the size of R and S. + // * 1 byte for S itself. + // * 1 byte for the sighash type. + if (lenR > (sig.size() - 8)) { + 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; + // + // /!\ This check can only be performed after we checked that lenR is + // consistent with the size of the signature or we risk to access out of + // bound elements. + if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) { + return false; + } + + // + // Check that S is an positive integer of sensible size. + // + + // S's definition starts after R's definition: + // * 1 byte for the coumpound type. + // * 1 byte for the length of the signature. + // * 1 byte for the size of R. + // * lenR bytes for R itself. + // * 1 byte to get to S. + const uint32_t startS = lenR + 4; // Check whether the S element is an integer. - if (sig[lenR + 4] != 0x02) return false; + if (sig[startS] != 0x02) { + return false; + } + + // Extract the length of the S element. + const uint32_t lenS = sig[startS + 1]; // Zero-length integers are not allowed for S. - if (lenS == 0) return false; + if (lenS == 0) { + return false; + } // Negative numbers are not allowed for S. - if (sig[lenR + 6] & 0x80) return false; + if (sig[startS + 2] & 0x80) { + return false; + } + + // Verify that the length of S is consistent with the size of the signature + // including metadatas: + // * 1 byte for the integer type of S. + // * 1 byte for the size of S. + // * 1 byte for the sighash type. + if (size_t(startS + lenS + 3) != sig.size()) { + 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)) { + // + // /!\ This check can only be performed after we checked that lenR and lenS + // are consistent with the size of the signature or we risk to access + // out of bound elements. + if (lenS > 1 && (sig[startS + 2] == 0x00) && !(sig[startS + 3] & 0x80)) { return false; } return true; } static bool IsLowDERSignature(const valtype &vchSig, ScriptError *serror) { assert(vchSig.size() > 0); if (CPubKey::CheckLowS(vchSig | boost::adaptors::sliced(0, vchSig.size() - 1))) { return true; } return set_error(serror, SCRIPT_ERR_SIG_HIGH_S); } bool CheckSignatureEncoding(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; } if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsValidSignatureEncoding(vchSig)) { return set_error(serror, SCRIPT_ERR_SIG_DER); } if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) { // serror is set return false; } if ((flags & SCRIPT_VERIFY_STRICTENC) != 0) { if (!GetHashType(vchSig).isDefined()) { return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE); } bool usesForkId = GetHashType(vchSig).hasForkId(); bool forkIdEnabled = flags & SCRIPT_ENABLE_SIGHASH_FORKID; if (!forkIdEnabled && usesForkId) { return set_error(serror, SCRIPT_ERR_ILLEGAL_FORKID); } if (forkIdEnabled && !usesForkId) { return set_error(serror, SCRIPT_ERR_MUST_USE_FORKID); } } return true; } static bool IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { switch (vchPubKey.size()) { case 33: // Compressed public key: must start with 0x02 or 0x03. return vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03; case 65: // Non-compressed public key: must start with 0x04. return vchPubKey[0] == 0x04; default: // Non-canonical public key: invalid size. return false; } } static bool IsCompressedPubKey(const valtype &vchPubKey) { if (vchPubKey.size() != 33) { // Non-canonical public key: invalid length for compressed key return false; } if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) { // Non-canonical public key: invalid prefix for compressed key return false; } return true; } bool CheckPubKeyEncoding(const valtype &vchPubKey, uint32_t flags, ScriptError *serror) { if ((flags & SCRIPT_VERIFY_STRICTENC) && !IsCompressedOrUncompressedPubKey(vchPubKey)) { return set_error(serror, SCRIPT_ERR_PUBKEYTYPE); } // Only compressed keys are accepted when // SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is enabled. if ((flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) && !IsCompressedPubKey(vchPubKey)) { return set_error(serror, SCRIPT_ERR_NONCOMPRESSED_PUBKEY); } return true; }