aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSimon Warta <[email protected]>2015-08-10 22:53:58 +0200
committerSimon Warta <[email protected]>2015-08-10 23:00:30 +0200
commit170cd1c2b92de39cd6a5f6adae56b470f0bf3898 (patch)
tree62cddee633a8225f813a3422ccb79492d9134cf7 /src
parent480999c2820b0da995108d7474a74755cafd2924 (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.
Diffstat (limited to 'src')
-rw-r--r--src/lib/utils/parsing.cpp19
-rw-r--r--src/tests/catchy/test_utils.cpp42
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"));
+ }