diff options
author | Simon Warta <[email protected]> | 2015-08-10 22:53:58 +0200 |
---|---|---|
committer | Simon Warta <[email protected]> | 2015-08-10 23:00:30 +0200 |
commit | 170cd1c2b92de39cd6a5f6adae56b470f0bf3898 (patch) | |
tree | 62cddee633a8225f813a3422ccb79492d9134cf7 | |
parent | 480999c2820b0da995108d7474a74755cafd2924 (diff) |
Avoid integer overlow in string->uint32 converter
On systems where unsigned long is uint64 (typically 64 bit systems), a
string containing a number greater than 2^32-1 was sucessfully converted
to a uint64 and than reduced to uint32, causing an overflow. E.g.
to_u32bit("4294967296") was 0 and to_u32bit("4294967297") was 1.
-rw-r--r-- | src/lib/utils/parsing.cpp | 19 | ||||
-rw-r--r-- | src/tests/catchy/test_utils.cpp | 42 |
2 files changed, 58 insertions, 3 deletions
diff --git a/src/lib/utils/parsing.cpp b/src/lib/utils/parsing.cpp index 36b168290..605823082 100644 --- a/src/lib/utils/parsing.cpp +++ b/src/lib/utils/parsing.cpp @@ -1,6 +1,7 @@ /* * Various string utils and parsing functions * (C) 1999-2007,2013,2014 Jack Lloyd +* (C) 2015 Simon Warta (Kullo GmbH) * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -9,6 +10,7 @@ #include <botan/exceptn.h> #include <botan/charset.h> #include <botan/get_byte.h> +#include <limits> #include <set> #include <stdexcept> @@ -18,11 +20,22 @@ u32bit to_u32bit(const std::string& str) { try { - return std::stoul(str, nullptr); + const auto integerValue = std::stoul(str); + + // integerValue might be uint64 + if (integerValue > std::numeric_limits<u32bit>::max()) + { + throw Invalid_Argument("Integer value exceeds 32 bit range: " + std::to_string(integerValue)); + } + + return integerValue; } - catch(std::exception&) + catch(std::exception& e) { - throw std::runtime_error("Could not read '" + str + "' as decimal string"); + auto message = std::string("Could not read '" + str + "' as decimal string"); + auto exceptionMessage = std::string(e.what()); + if (!exceptionMessage.empty()) message += ": " + exceptionMessage; + throw std::runtime_error(message); } } diff --git a/src/tests/catchy/test_utils.cpp b/src/tests/catchy/test_utils.cpp index a04010b8f..b63076c4f 100644 --- a/src/tests/catchy/test_utils.cpp +++ b/src/tests/catchy/test_utils.cpp @@ -4,6 +4,7 @@ #include "catchy_tests.h" #include <botan/calendar.h> +#include <botan/parsing.h> #include <botan/internal/rounding.h> using namespace Botan; @@ -166,3 +167,44 @@ TEST_CASE("calendar_point to stl timepoint and back", "[utils]") CHECK_THROWS( in.to_std_timepoint() ); } } + +TEST_CASE("uint32 parsing valid", "[utils]") + { + CHECK_THAT(to_u32bit("0"), Equals(0)); + CHECK_THAT(to_u32bit("1"), Equals(1)); + CHECK_THAT(to_u32bit("2"), Equals(2)); + CHECK_THAT(to_u32bit("10"), Equals(10)); + CHECK_THAT(to_u32bit("100"), Equals(100)); + CHECK_THAT(to_u32bit("1000"), Equals(1000)); + CHECK_THAT(to_u32bit("10000"), Equals(10000)); + CHECK_THAT(to_u32bit("100000"), Equals(100000)); + CHECK_THAT(to_u32bit("1000000"), Equals(1000000)); + // biggest allowed value + CHECK_THAT(to_u32bit("4294967295"), Equals(4294967295)); + + // leading zeros + CHECK_THAT(to_u32bit("00"), Equals(0)); + CHECK_THAT(to_u32bit("01"), Equals(1)); + CHECK_THAT(to_u32bit("02"), Equals(2)); + CHECK_THAT(to_u32bit("010"), Equals(10)); + CHECK_THAT(to_u32bit("0000000000000000000000000010"), Equals(10)); + + // leading and trailing whitespace + CHECK_THAT(to_u32bit(" 1"), Equals(1)); + CHECK_THAT(to_u32bit(" 1 "), Equals(1)); + CHECK_THAT(to_u32bit("\n1"), Equals(1)); + CHECK_THAT(to_u32bit("1\n"), Equals(1)); + CHECK_THAT(to_u32bit("1 5"), Equals(1)); + CHECK_THAT(to_u32bit("1\t5"), Equals(1)); + CHECK_THAT(to_u32bit("1\n5"), Equals(1)); + + // invalid input + CHECK_THROWS(to_u32bit("")); + CHECK_THROWS(to_u32bit(" ")); + CHECK_THROWS(to_u32bit("!")); + //CHECK_THROWS(to_u32bit("1!")); + CHECK_THROWS(to_u32bit("!1")); + + // Avoid overflow: value too big for uint32 + CHECK_THROWS(to_u32bit("4294967296")); + } |