diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp --- a/src/script/sigencoding.cpp +++ b/src/script/sigencoding.cpp @@ -38,53 +38,119 @@ // 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; }