Skip to content

Commit

Permalink
keychain: ValidityPeriod implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
yoursunny committed Jun 21, 2020
1 parent 132ff1f commit dccc8d7
Show file tree
Hide file tree
Showing 11 changed files with 297 additions and 183 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ addons:
- ninja-build

before_install:
- pip install cpp-coveralls cmake meson
- pip install cmake cpp-coveralls meson

install:
- |
Expand Down
147 changes: 139 additions & 8 deletions src/ndnph/keychain/validity-period.hpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,162 @@
#ifndef NDNPH_KEYCHAIN_VALIDITY_PERIOD_HPP
#define NDNPH_KEYCHAIN_VALIDITY_PERIOD_HPP

#include "../tlv/encoder.hpp"
#include "../an.hpp"
#include "../tlv/ev-decoder.hpp"
#include "../tlv/value.hpp"
#include <time.h>

namespace ndnph {
namespace detail {

/** @brief ValidityPeriod stub. */
class UtcTimezone
{
public:
UtcTimezone()
{
const char* tz = getenv("TZ");
if (tz == nullptr) {
m_tz[0] = '\0';
} else {
strncpy(m_tz, tz, sizeof(m_tz));
}
setenv("TZ", "UTC", 1);
}

~UtcTimezone()
{
if (m_tz[0] != '\0') {
setenv("TZ", m_tz, 1);
}
}

private:
char m_tz[64];
};

} // namespace ndnph

/** @brief ValidityPeriod of a certificate. */
class ValidityPeriod
{
public:
/** @brief Get a very long ValidityPeriod. */
static ValidityPeriod getMax()
{
return ValidityPeriod(540109800, 253402300799);
}

ValidityPeriod() = default;

ValidityPeriod(time_t notBefore, time_t notAfter)
: notBefore(notBefore)
, notAfter(notAfter)
{}

/** @brief Determine whether the specified timestamp is within validity period. */
bool includes(time_t t)
{
return notBefore <= t && t <= notAfter;
}

void encodeTo(Encoder& encoder) const
{
const char* stubNotBefore = "20200212T000000";
const char* stubNotAfter = "20201030T235959";
encoder.prependTlv(
TT::ValidityPeriod,
[=](Encoder& encoder) {
[this](Encoder& encoder) {
char buf[TIMESTAMP_BUFLEN];
printTimestamp(buf, notBefore);
encoder.prependTlv(TT::NotBefore,
tlv::Value(reinterpret_cast<const uint8_t*>(stubNotBefore), 15));
tlv::Value(reinterpret_cast<const uint8_t*>(buf), TIMESTAMP_LEN));
},
[=](Encoder& encoder) {
[this](Encoder& encoder) {
char buf[TIMESTAMP_BUFLEN];
printTimestamp(buf, notAfter);
encoder.prependTlv(TT::NotAfter,
tlv::Value(reinterpret_cast<const uint8_t*>(stubNotAfter), 15));
tlv::Value(reinterpret_cast<const uint8_t*>(buf), TIMESTAMP_LEN));
});
}

bool decodeFrom(const Decoder::Tlv& input)
{
return EvDecoder::decode(input, { TT::ValidityPeriod },
EvDecoder::def<TT::NotBefore>([this](const Decoder::Tlv& d) {
return decodeTimestamp(d, &notBefore);
}),
EvDecoder::def<TT::NotAfter>([this](const Decoder::Tlv& d) {
return decodeTimestamp(d, &notAfter);
}));
}

private:
static constexpr size_t TIMESTAMP_LEN = 15;
static constexpr size_t TIMESTAMP_BUFLEN = TIMESTAMP_LEN + 1;

static const char* getTimestampFormat()
{
return "%04d%02d%02dT%02d%02d%02d";
}

static void printTimestamp(char buf[TIMESTAMP_BUFLEN], time_t t)
{
struct tm* m = gmtime(&t);
if (m == nullptr) {
memset(buf, 0, TIMESTAMP_BUFLEN);
return;
}
snprintf(buf, TIMESTAMP_BUFLEN, getTimestampFormat(), 1900 + m->tm_year, 1 + m->tm_mon,
m->tm_mday, m->tm_hour, m->tm_min, m->tm_sec);
}

static bool decodeTimestamp(const Decoder::Tlv& d, time_t* v)
{
if (d.length != TIMESTAMP_LEN) {
return false;
}

char buf[TIMESTAMP_BUFLEN];
std::copy_n(d.value, TIMESTAMP_LEN, buf);
buf[TIMESTAMP_LEN] = '\0';

struct tm m = {};
if (sscanf(buf, getTimestampFormat(), &m.tm_year, &m.tm_mon, &m.tm_mday, &m.tm_hour, &m.tm_min,
&m.tm_sec) != 6) {
return false;
}
m.tm_year -= 1900;
m.tm_mon -= 1;

detail::UtcTimezone useUtc;
*v = mktime(&m);
return *v >= 0;
}

public:
/** @brief NotBefore field in seconds since Unix epoch. */
time_t notBefore = 0;

/** @brief NotAfter field in seconds since Unix epoch. */
time_t notAfter = 0;
};

inline bool
operator==(const ValidityPeriod& lhs, const ValidityPeriod& rhs)
{
return lhs.notBefore == rhs.notBefore && lhs.notAfter == rhs.notAfter;
}

NDNPH_DECLARE_NE(ValidityPeriod, inline)

/** @brief Compute the intersection of two ValidityPeriods. */
inline ValidityPeriod
operator&&(const ValidityPeriod& lhs, const ValidityPeriod& rhs)
{
ValidityPeriod intersection;
intersection.notBefore = std::max(lhs.notBefore, rhs.notBefore);
intersection.notAfter = std::min(lhs.notAfter, rhs.notAfter);
return intersection;
}

} // namespace ndnph

#endif // NDNPH_KEYCHAIN_VALIDITY_PERIOD_HPP
2 changes: 1 addition & 1 deletion src/ndnph/packet/component.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ operator==(const Component& lhs, const Component& rhs)
return lhs.size() == rhs.size() && std::equal(lhs.tlv(), lhs.tlv() + lhs.size(), rhs.tlv());
}

NDNPH_DECLARE_NE(Component, inline);
NDNPH_DECLARE_NE(Component, inline)

} // namespace ndnph

Expand Down
26 changes: 26 additions & 0 deletions tests/test-common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@

#include <atomic>
#include <chrono>
#include <cstring>
#include <string>
#include <thread>
#include <vector>

#include <boost/concept_check.hpp>
#include <boost/lexical_cast.hpp>
Expand All @@ -15,6 +18,29 @@ namespace g = testing;
namespace ndnph {
namespace test {

inline std::vector<uint8_t>
fromHex(const std::string& input)
{
std::vector<uint8_t> v;
v.reserve(input.size() / 2);
static const char* hexDigits = "0123456789ABCDEF";
int last = -1;
for (char ch : input) {
const char* digit = strchr(hexDigits, ch);
if (digit == nullptr) {
continue;
}
int nibble = digit - hexDigits;
if (last < 0) {
last = nibble;
} else {
v.push_back(static_cast<uint8_t>((last << 4) | nibble));
last = -1;
}
}
return v;
}

template<typename T>
std::string
toString(const T& obj)
Expand Down
80 changes: 80 additions & 0 deletions tests/unit/keychain/validity-period.t.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "ndnph/keychain/validity-period.hpp"

#include "test-common.hpp"

namespace ndnph {
namespace {

TEST(ValidityPeriod, Normal)
{
auto wire = test::fromHex("FD00FD26"
"FD00FE0F 323031383131313354303835383439" // 20181113T085849
"FD00FF0F 323032303130313154313633383033" // 20201011T163803
);
ValidityPeriod vp;
vp.notBefore = 1542099529;
vp.notAfter = 1602434283;
{
StaticRegion<1024> region;
Encoder encoder(region);
bool ok = encoder.prepend(vp);
ASSERT_TRUE(ok);
EXPECT_THAT(std::vector<uint8_t>(encoder.begin(), encoder.end()), g::ElementsAreArray(wire));
}

ValidityPeriod decoded;
ASSERT_TRUE(Decoder(wire.data(), wire.size()).decode(decoded));
EXPECT_EQ(decoded.notBefore, 1542099529);
EXPECT_EQ(decoded.notAfter, 1602434283);
}

TEST(ValidityPeriod, DecodeBadLength)
{
auto wire = test::fromHex("FD00FD25"
"FD00FE0F 323031383131313354303835383439" // 20181113T085849
"FD00FF0E 3230323031303131543136333830" // 20201011T16380
); // NotAfter is missing one byte
ValidityPeriod vp;
EXPECT_FALSE(Decoder(wire.data(), wire.size()).decode(vp));
}

TEST(ValidityPeriod, DecodeBadValue)
{
auto wire = test::fromHex("FD00FD25"
"FD00FE0F 323031383131313341303835383439" // 20181113A085849
"FD00FF0E 323032303130313154313633383033" // 20201011T163803
); // NotBefore has 'A' instead of 'T'
ValidityPeriod vp;
EXPECT_FALSE(Decoder(wire.data(), wire.size()).decode(vp));
}

TEST(ValidityPeriod, Includes)
{
ValidityPeriod vp(1542099529, 1602434283);
EXPECT_FALSE(vp.includes(1083820612));
EXPECT_FALSE(vp.includes(1542099528));
EXPECT_TRUE(vp.includes(1542099529));
EXPECT_TRUE(vp.includes(1569790373));
EXPECT_TRUE(vp.includes(1602434283));
EXPECT_FALSE(vp.includes(1602434284));
EXPECT_FALSE(vp.includes(1927427784));

vp = ValidityPeriod();
EXPECT_FALSE(vp.includes(1083820612));
EXPECT_FALSE(vp.includes(1569790373));
EXPECT_FALSE(vp.includes(1927427784));
}

TEST(ValidityPeriod, Intersect)
{
ValidityPeriod vp1(1542099529, 1602434283);
ValidityPeriod vp2(1543017600, 1609372800);
EXPECT_EQ((vp1 && vp2).notBefore, 1543017600);
EXPECT_EQ((vp1 && vp2).notAfter, 1602434283);

ValidityPeriod vp0 = ValidityPeriod::getMax() && vp1 && vp2;
EXPECT_EQ(vp0, ValidityPeriod(1543017600, 1602434283));
}

} // namespace
} // namespace ndnph
2 changes: 1 addition & 1 deletion tests/unit/meson.build
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
unittest_files = files(
'app/ping.t.cpp','app/rdr.t.cpp','app/segment.t.cpp','core/region.t.cpp','core/simple-queue.t.cpp','face/face.t.cpp','face/transport.t.cpp','keychain/certificate.t.cpp','keychain/digest-key.t.cpp','keychain/ecdsa-key.t.cpp','packet/component.t.cpp','packet/convention.t.cpp','packet/data.t.cpp','packet/interest.t.cpp','packet/nack.t.cpp','packet/name.t.cpp','tlv/decoder.t.cpp','tlv/encoder.t.cpp','tlv/ev-decoder.t.cpp','tlv/nni.t.cpp','tlv/varnum.t.cpp'
'app/ping.t.cpp','app/rdr.t.cpp','app/segment.t.cpp','core/region.t.cpp','core/simple-queue.t.cpp','face/face.t.cpp','face/transport.t.cpp','keychain/certificate.t.cpp','keychain/digest-key.t.cpp','keychain/ecdsa-key.t.cpp','keychain/validity-period.t.cpp','packet/component.t.cpp','packet/convention.t.cpp','packet/data.t.cpp','packet/interest.t.cpp','packet/nack.t.cpp','packet/name.t.cpp','tlv/decoder.t.cpp','tlv/encoder.t.cpp','tlv/ev-decoder.t.cpp','tlv/nni.t.cpp','tlv/varnum.t.cpp'
)
29 changes: 7 additions & 22 deletions tests/unit/packet/data.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,7 @@ TEST(Data, EncodeMinimal)
EXPECT_EQ(data.getIsFinalBlock(), false);
EXPECT_THAT(data.getContent(), g::SizeIs(0));

std::vector<uint8_t> wire({
0x06, 0x0C, // Data
0x07, 0x03, 0x08, 0x01, 0x41, // Name
0x16, 0x03, 0x1B, 0x01, 0xC8, // DSigInfo
0x17, 0x00, // DSigValue
});
auto wire = test::fromHex("060C name=0703080141 siginfo=16031B01C8 sigvalue=1700");
data.setName(Name(&wire[4], 3));

Encoder encoder(region);
Expand All @@ -48,22 +43,12 @@ TEST(Data, EncodeFull)
Data data = region.create<Data>();
ASSERT_FALSE(!data);

std::vector<uint8_t> wire({
0x64, 0x3A, // LpPacket
0x62, 0x08, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, // PitToken
0x50, 0x2E, // LpPayload
0x06, 0x2C, // Data
0x07, 0x06, 0x08, 0x01, 0x41, 0x08, 0x01, 0x42, // Name
0x14, 0x0C, // MetaInfo
0x18, 0x01, 0x01, // MetaInfo.ContentType
0x19, 0x02, 0x01, 0xF4, // MetaInfo.FreshnessPeriod
0x1A, 0x03, 0x08, 0x01, 0x42, // MetaInfo.FinalBlockId
0x15, 0x02, 0xC0, 0xC1, // Content
0x16, 0x0A, // DSigInfo
0x1B, 0x01, 0x10, // DSigInfo.SigType
0x1C, 0x05, 0x07, 0x03, 0x08, 0x01, 0x4B, // DSigInfo.KeyLocator
0x17, 0x04, 0xF0, 0xF1, 0xF2, 0xF3 // DSigValue
});
auto wire =
test::fromHex("lppacket=643A pittoken=6208B0B1B2B3B4B5B6B7 lppayload=502E data=062C"
"name=0706080141080142 metainfo=140C contenttype=180101 freshness=190201F4 "
"finalblock=1A03080142"
"content=1502C0C1"
"siginfo=160A sigtype=1B0110 keylocator=1C05070308014B sigvalue=1704F0F1F2F3");
data.setName(Name::parse(region, "/A/B"));
data.setContentType(0x01);
data.setFreshnessPeriod(500);
Expand Down
13 changes: 1 addition & 12 deletions tests/unit/tlv/decoder.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,7 @@ namespace {

TEST(Decoder, DecodeGood)
{
std::vector<uint8_t> wire({
0x01,
0x00, // 0100
0x02, 0x01,
0xA1, // 0201 A1
0xFD, 0x00, 0xFD, 0x03, 0xA3, 0xA3,
0xA3, // FD03 A3A3A3
0xFD, 0x01, 0x00, 0x02, 0xA2,
0xA2, // 010002 A2A2
0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01,
0xA1, // FFFFFFFF A1
});
auto wire = test::fromHex("t01l00 t02l01vA1 tFD00FDl03vA3A3A3 tFD0100l02vA2A2 tFEFFFFFFFFl01vA1");
Decoder decoder(wire.data(), wire.size());

auto it = decoder.begin(), end = decoder.end();
Expand Down
Loading

0 comments on commit dccc8d7

Please sign in to comment.