security: avoid ValidityPeriod under/overflow

refs #5176

Change-Id: I15f2225ea727b205798db29d14ef49a7565eb82e
This commit is contained in:
Junxiao Shi committed 2023-07-24 11:09:27 +00:00
1 parent f81de71486
commit 502c4c3bd6
3 files changed
+127 -41

No files matched your search

+41 -10
View File
@@ -45,9 +45,8 @@ ValidityPeriod::ValidityPeriod()
ValidityPeriod::ValidityPeriod(const time::system_clock::time_point& notBefore,
const time::system_clock::time_point& notAfter)
: m_notBefore(time_point_cast<TimePoint::duration>(notBefore + TimePoint::duration(1) -
time::system_clock::time_point::duration(1)))
, m_notAfter(time_point_cast<TimePoint::duration>(notAfter))
: m_notBefore(toTimePointCeil(notBefore))
, m_notAfter(toTimePointFloor(notAfter))
{
}
@@ -114,24 +113,56 @@ ValidityPeriod::wireDecode(const Block& wire)
}
try {
m_notBefore = time_point_cast<TimePoint::duration>(
time::fromIsoString(readString(m_wire.elements()[NOT_BEFORE_OFFSET])));
m_notAfter = time_point_cast<TimePoint::duration>(
time::fromIsoString(readString(m_wire.elements()[NOT_AFTER_OFFSET])));
m_notBefore = decodeTimePoint(m_wire.elements()[NOT_BEFORE_OFFSET]);
m_notAfter = decodeTimePoint(m_wire.elements()[NOT_AFTER_OFFSET]);
}
catch (const std::bad_cast&) {
NDN_THROW(Error("Invalid date format in NOT-BEFORE or NOT-AFTER field"));
}
}
ValidityPeriod::TimePoint
ValidityPeriod::toTimePointFloor(const time::system_clock::time_point& t)
{
return TimePoint(boost::chrono::floor<TimePoint::duration>(t.time_since_epoch()));
}
ValidityPeriod::TimePoint
ValidityPeriod::toTimePointCeil(const time::system_clock::time_point& t)
{
return TimePoint(boost::chrono::ceil<TimePoint::duration>(t.time_since_epoch()));
}
ValidityPeriod::TimePoint
ValidityPeriod::decodeTimePoint(const Block& element)
{
// Bug #5176, prevent time::system_clock::time_point under/overflow
static const auto minTime = toTimePointCeil(time::system_clock::time_point::min());
static const auto maxTime = toTimePointFloor(time::system_clock::time_point::max());
static const auto minValue = time::toIsoString(minTime);
static const auto maxValue = time::toIsoString(maxTime);
BOOST_ASSERT(minValue.size() == ISO_DATETIME_SIZE);
BOOST_ASSERT(maxValue.size() == ISO_DATETIME_SIZE);
auto value = readString(element);
BOOST_ASSERT(value.size() == ISO_DATETIME_SIZE);
if (value < minValue) {
return minTime;
}
if (value > maxValue) {
return maxTime;
}
return time_point_cast<TimePoint::duration>(time::fromIsoString(value));
}
ValidityPeriod&
ValidityPeriod::setPeriod(const time::system_clock::time_point& notBefore,
const time::system_clock::time_point& notAfter)
{
m_wire.reset();
m_notBefore = time_point_cast<TimePoint::duration>(notBefore + TimePoint::duration(1) -
time::system_clock::time_point::duration(1));
m_notAfter = time_point_cast<TimePoint::duration>(notAfter);
m_notBefore = toTimePointCeil(notBefore);
m_notAfter = toTimePointFloor(notAfter);
return *this;
}
+45 -26
View File
@@ -53,67 +53,88 @@ public:
makeRelative(time::seconds validFrom, time::seconds validUntil,
const time::system_clock::time_point& now = time::system_clock::now());
/** @brief Set validity period [UNIX epoch + 1 nanosecond, UNIX epoch] that is always invalid
/**
* @brief Create a validity period that is invalid for any timepoint.
*/
ValidityPeriod();
/** @brief Create validity period from @p block
/**
* @brief Decode validity period from @p block .
*/
explicit
ValidityPeriod(const Block& block);
/** @brief Create validity period [@p notBefore, @p notAfter]
* @param notBefore exclusive beginning of the validity period range
* @param notAfter exclusive end of the validity period range
*
* @note The supplied time points will be rounded up to the whole seconds:
* - @p notBefore is rounded up the next whole second
* - @p notAfter is truncated to the previous whole second
/**
* @brief Create validity period [@p notBefore, @p notAfter].
* @param notBefore exclusive beginning of the validity period range,
* to be rounded up to the next whole second.
* @param notAfter exclusive end of the validity period range,
* to be rounded down to the previous whole second.
*/
ValidityPeriod(const time::system_clock::time_point& notBefore,
const time::system_clock::time_point& notAfter);
/** @brief Check if @p now falls within the validity period
* @param now Time point to check if it falls within the period
* @return periodBegin <= @p now and @p now <= periodEnd
/**
* @brief Check if @p now falls within the validity period.
* @param now Time point to check if it falls within the period
* @return notBefore <= @p now and @p now <= notAfter.
*/
bool
isValid(const time::system_clock::time_point& now = time::system_clock::now()) const;
/** @brief Set validity period [@p notBefore, @p notAfter]
* @param notBefore exclusive beginning of the validity period range
* @param notAfter exclusive end of the validity period range
*
* @note The supplied time points will be rounded up to the whole seconds:
* - @p notBefore is rounded up the next whole second
* - @p notAfter is truncated to the previous whole second
/**
* @brief Set validity period [@p notBefore, @p notAfter].
* @param notBefore exclusive beginning of the validity period range,
* to be rounded up to the next whole second.
* @param notAfter exclusive end of the validity period range,
* to be rounded down to the previous whole second.
*/
ValidityPeriod&
setPeriod(const time::system_clock::time_point& notBefore,
const time::system_clock::time_point& notAfter);
/** @brief Get the stored validity period
/**
* @brief Get the stored validity period.
*/
std::pair<time::system_clock::time_point, time::system_clock::time_point>
getPeriod() const;
/** @brief Fast encoding or block size estimation
/**
* @brief Fast encoding or block size estimation.
*/
template<encoding::Tag TAG>
size_t
wireEncode(EncodingImpl<TAG>& encoder) const;
/** @brief Encode ValidityPeriod into TLV block
/**
* @brief Encode ValidityPeriod into TLV block.
*/
const Block&
wireEncode() const;
/** @brief Decode ValidityPeriod from TLV block
* @throw Error when an invalid TLV block supplied
/**
* @brief Decode ValidityPeriod from TLV block.
* @throw Error when an invalid TLV block supplied.
*
* @note If either timestamp in @p wire is earlier than 1677-09-21 or later than 2262-04-11,
* it will be adjusted to these dates so that they are representable as
* @c time::system_clock::time_point type returned by getPeriod() method.
*/
void
wireDecode(const Block& wire);
private:
using TimePoint = boost::chrono::time_point<time::system_clock, time::seconds>;
static TimePoint
toTimePointFloor(const time::system_clock::time_point& t);
static TimePoint
toTimePointCeil(const time::system_clock::time_point& t);
static TimePoint
decodeTimePoint(const Block& element);
private: // EqualityComparable concept
// NOTE: the following "hidden friend" operators are available via
// argument-dependent lookup only and must be defined inline.
@@ -132,8 +153,6 @@ private: // EqualityComparable concept
}
private:
using TimePoint = boost::chrono::time_point<time::system_clock, time::seconds>;
TimePoint m_notBefore;
TimePoint m_notAfter;
+41 -5
View File
@@ -99,10 +99,25 @@ BOOST_FIXTURE_TEST_CASE(ConstructorSetter, ClockFixture)
"(19700101T000000, 19791230T000000)");
validity1.setPeriod(time::getUnixEpoch() + 1_ns,
time::getUnixEpoch() + (10 * 365_days) + 1_ns);
time::getUnixEpoch() + 3650_days + 1_ns);
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(validity1),
"(19700101T000001, 19791230T000000)");
validity1.setPeriod(time::getUnixEpoch() + 999999999_ns,
time::getUnixEpoch() + 3650_days + 999999999_ns);
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(validity1),
"(19700101T000001, 19791230T000000)");
validity1.setPeriod(time::getUnixEpoch() - 2_days + 1_ns,
time::getUnixEpoch() - 1_day + 1_ns);
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(validity1),
"(19691230T000001, 19691231T000000)");
validity1.setPeriod(time::getUnixEpoch() - 2_days + 999999999_ns,
time::getUnixEpoch() - 1_day + 999999999_ns);
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(validity1),
"(19691230T000001, 19691231T000000)");
BOOST_CHECK_EQUAL(ValidityPeriod(now, now).isValid(), true);
BOOST_CHECK_EQUAL(ValidityPeriod(now + 1_s, now).isValid(), false);
}
@@ -129,8 +144,28 @@ BOOST_AUTO_TEST_CASE(EncodingDecoding)
BOOST_CHECK(v1.getPeriod() == v2.getPeriod());
}
const uint8_t VP2[] = {
0xfd, 0x00, 0xfd, 0x26, // ValidityPeriod
0xfd, 0x00, 0xfe, 0x0f, // NotBefore
0x30, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, // 00010101T000000
0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0xfd, 0x00, 0xff, 0x0f, // NotAfter
0x39, 0x39, 0x39, 0x39, 0x31, 0x32, 0x33, 0x31, // 99991231T235959
0x54, 0x32, 0x33, 0x35, 0x39, 0x35, 0x39
};
BOOST_AUTO_TEST_CASE(DecodingLarge)
{
ValidityPeriod v(Block{VP2});
BOOST_CHECK(v.isValid(time::fromIsoString("16770921T001245")));
BOOST_CHECK(v.isValid(time::fromIsoString("19010120T120000")));
BOOST_CHECK(v.isValid(time::fromIsoString("20230725T120000")));
BOOST_CHECK(v.isValid(time::fromIsoString("22001030T120000")));
BOOST_CHECK(v.isValid(time::fromIsoString("22620411T234716")));
}
const uint8_t VP_E1[] = {
0xfd, 0x00, 0xff, 0x26, // ValidityPeriod (error)
0xfd, 0x00, 0xff, 0x26, // ValidityPeriod (wrong TLV-TYPE)
0xfd, 0x00, 0xfe, 0x0f, // NotBefore
0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, // 19700101T000000
0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
@@ -141,7 +176,7 @@ const uint8_t VP_E1[] = {
const uint8_t VP_E2[] = {
0xfd, 0x00, 0xfd, 0x26, // ValidityPeriod
0xfd, 0x00, 0xff, 0x0f, // NotBefore (error)
0xfd, 0x00, 0xff, 0x0f, // NotBefore (wrong TLV-TYPE)
0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, // 19700101T000000
0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0xfd, 0x00, 0xff, 0x0f, // NotAfter
@@ -154,7 +189,7 @@ const uint8_t VP_E3[] = {
0xfd, 0x00, 0xfe, 0x0f, // NotBefore
0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, // 19700101T000000
0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0xfd, 0x00, 0xfe, 0x0f, // NotAfter (error)
0xfd, 0x00, 0xfe, 0x0f, // NotAfter (wrong TLV-TYPE)
0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x32, // 19700102T000000
0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
};
@@ -167,7 +202,7 @@ const uint8_t VP_E4[] = {
0xfd, 0x00, 0xff, 0x0f, // NotAfter
0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x32, // 19700102T000000
0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
0xfd, 0x00, 0xff, 0x0f, // NotAfter (error)
0xfd, 0x00, 0xff, 0x0f, // NotAfter (duplicate)
0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x32, // 19700102T000000
0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
};
@@ -177,6 +212,7 @@ const uint8_t VP_E5[] = {
0xfd, 0x00, 0xfe, 0x0f, // NotBefore
0x31, 0x39, 0x37, 0x30, 0x30, 0x31, 0x30, 0x31, // 19700101T000000
0x54, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30
// missing NotAfter
};
const uint8_t VP_E6[] = {