security: avoid ValidityPeriod under/overflow
refs #5176 Change-Id: I15f2225ea727b205798db29d14ef49a7565eb82e
This commit is contained in:
1 parent
f81de71486
commit
502c4c3bd6
3 files changed
+127
-41
No files matched your search
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
Reference in new issue
Block a user