♻️ refactor: Extract Instant struct
parent
026db25ba7
commit
fb1e133ca1
|
@ -48,7 +48,7 @@ bool is_pubkey_length (const vector <uint8_t> & v) {
|
|||
optional <vector <uint8_t>> try_verify_signed_data (
|
||||
const ExpiringSignature & sig,
|
||||
const vector <uint8_t> & pubkey,
|
||||
int64_t now
|
||||
Instant now
|
||||
) {
|
||||
try_sodium_init ();
|
||||
|
||||
|
@ -67,13 +67,12 @@ optional <vector <uint8_t>> try_verify_signed_data (
|
|||
|
||||
const json j = json::parse (sig.cert_s);
|
||||
|
||||
const int64_t not_before = j ["not_before"];
|
||||
const int64_t not_after = j ["not_after"];
|
||||
const TimeRange tr {
|
||||
j ["not_before"],
|
||||
j ["not_after"]
|
||||
};
|
||||
|
||||
if (now < not_before) {
|
||||
return nullopt;
|
||||
}
|
||||
if (now > not_after) {
|
||||
if (! tr.contains (now)) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
|
@ -86,7 +85,7 @@ optional <vector <uint8_t>> try_verify_signed_data (
|
|||
optional <vector <uint8_t>> verify_signed_data (
|
||||
const ExpiringSignature & sig,
|
||||
const vector <uint8_t> & pubkey,
|
||||
int64_t now
|
||||
Instant now
|
||||
) {
|
||||
try {
|
||||
return try_verify_signed_data (sig, pubkey, now);
|
||||
|
@ -100,7 +99,7 @@ optional <vector <uint8_t>> verify_cert_and_data (
|
|||
const ExpiringSignature & signed_cert,
|
||||
const ExpiringSignature & signed_data,
|
||||
const vector <uint8_t> & root_pubkey,
|
||||
int64_t now
|
||||
Instant now
|
||||
) {
|
||||
auto subkey_opt = verify_signed_data (signed_cert, root_pubkey, now);
|
||||
if (! subkey_opt) {
|
||||
|
@ -116,14 +115,14 @@ optional <vector <uint8_t>> verify_cert_and_data (
|
|||
const ExpiringSignature & signed_data,
|
||||
const vector <uint8_t> & root_pubkey
|
||||
) {
|
||||
return verify_cert_and_data (signed_cert, signed_data, root_pubkey, get_seconds_since_epoch ());
|
||||
return verify_cert_and_data (signed_cert, signed_data, root_pubkey, Instant::now ());
|
||||
}
|
||||
|
||||
optional <vector <uint8_t>> verify_signed_data (
|
||||
const ExpiringSignature & sig,
|
||||
const vector <uint8_t> & pubkey
|
||||
) {
|
||||
return verify_signed_data (sig, pubkey, get_seconds_since_epoch ());
|
||||
return verify_signed_data (sig, pubkey, Instant::now ());
|
||||
}
|
||||
|
||||
class SigningKey {
|
||||
|
@ -150,20 +149,17 @@ public:
|
|||
|
||||
optional <ExpiringSignature> sign_base64 (
|
||||
const string & payload_b64,
|
||||
int64_t duration,
|
||||
int64_t now
|
||||
TimeRange tr
|
||||
) const {
|
||||
try_sodium_init ();
|
||||
|
||||
if (duration > about_1_year) {
|
||||
if (tr.duration () > about_1_year) {
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
const auto not_after = now + duration;
|
||||
|
||||
const json j {
|
||||
{"not_before", now},
|
||||
{"not_after", not_after},
|
||||
{"not_before", tr.not_before},
|
||||
{"not_after", tr.not_after},
|
||||
{"payload_b64", payload_b64},
|
||||
};
|
||||
|
||||
|
@ -180,14 +176,14 @@ public:
|
|||
};
|
||||
}
|
||||
|
||||
optional <ExpiringSignature> sign_key (const SigningKey & k, int64_t now) const
|
||||
optional <ExpiringSignature> sign_key (const SigningKey & k, Instant now) const
|
||||
{
|
||||
return sign_base64 (k.pub_to_base64 (), about_3_months, now);
|
||||
return sign_base64 (k.pub_to_base64 (), TimeRange::from_start_and_dur (now, about_3_months));
|
||||
}
|
||||
|
||||
optional <ExpiringSignature> sign_data (const vector <uint8_t> & v, int64_t now) const
|
||||
optional <ExpiringSignature> sign_data (const vector <uint8_t> & v, Instant now) const
|
||||
{
|
||||
return sign_base64 (base64_encode (v), about_1_week, now);
|
||||
return sign_base64 (base64_encode (v), TimeRange::from_start_and_dur (now, about_1_week));
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -207,7 +203,7 @@ int happy_path () {
|
|||
SigningKey signing_key;
|
||||
cerr << "Signing key " << signing_key.pub_to_base64 () << endl;
|
||||
|
||||
const auto now = get_seconds_since_epoch ();
|
||||
const auto now = Instant::now ();
|
||||
|
||||
// That signing key signs some important data
|
||||
const auto important_data = copy_to_bytes ("Nikolai, Anna, Ivan, Mikhail, Ivan, Nikolai, Anna. 7 4 1 4 3 5 7 4");
|
||||
|
@ -219,7 +215,7 @@ int happy_path () {
|
|||
{
|
||||
// Check that a different time results in a different cert
|
||||
const auto cert_2 = std::move (*root_key.sign_key (signing_key, now));
|
||||
const auto cert_3 = std::move (*root_key.sign_key (signing_key, now + 1));
|
||||
const auto cert_3 = std::move (*root_key.sign_key (signing_key, Instant {now.x + 1}));
|
||||
|
||||
if (cert != cert_2) {
|
||||
cerr << "Certs should have been identical" << endl;
|
||||
|
|
|
@ -7,26 +7,66 @@ namespace BareMinimumCrypto {
|
|||
using namespace std;
|
||||
using namespace chrono;
|
||||
|
||||
int64_t get_seconds_since_epoch () {
|
||||
Instant::Instant (int64_t x): x (x) {}
|
||||
|
||||
Instant Instant::now () {
|
||||
const auto utc_now = system_clock::now ();
|
||||
return duration_cast <seconds> (utc_now.time_since_epoch ()).count ();
|
||||
return Instant {duration_cast <seconds> (utc_now.time_since_epoch ()).count ()};
|
||||
}
|
||||
|
||||
bool TimeRange::contains (Instant x) const {
|
||||
if (not_after < not_before) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.x < not_before) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (x.x > not_after) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t TimeRange::duration () const {
|
||||
return not_after - not_before;
|
||||
}
|
||||
|
||||
TimeRange TimeRange::from_start_and_dur (Instant start, int64_t dur) {
|
||||
return TimeRange {
|
||||
start.x,
|
||||
start.x + dur
|
||||
};
|
||||
}
|
||||
|
||||
// Most tests will use a virtual clock. But just as a smoke test,
|
||||
// make sure real time is realistic.
|
||||
|
||||
int test_time () {
|
||||
const auto seconds_since_epoch = get_seconds_since_epoch ();
|
||||
const auto now = Instant::now ();
|
||||
|
||||
const auto time_of_writing = 1610844872;
|
||||
if (seconds_since_epoch < time_of_writing) {
|
||||
cerr << "Error: Real time is in the past." << endl;
|
||||
const int64_t about_100_years = (int64_t)100 * 365 * 86400;
|
||||
|
||||
const TimeRange tr {
|
||||
time_of_writing,
|
||||
time_of_writing + about_100_years
|
||||
};
|
||||
|
||||
if (! tr.contains (now)) {
|
||||
cerr << "System clock is acting weird" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
const int64_t about_100_years = (int64_t)100 * 365 * 86400;
|
||||
if (seconds_since_epoch > time_of_writing + about_100_years) {
|
||||
cerr << "Error: Real time is in the far future." << endl;
|
||||
const TimeRange bad_tr {
|
||||
time_of_writing + about_100_years,
|
||||
time_of_writing
|
||||
};
|
||||
|
||||
if (bad_tr.contains (now)) {
|
||||
cerr << "Invalid TimeRange should not contain any Instants" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,23 @@ namespace BareMinimumCrypto {
|
|||
const int64_t about_3_months = (int64_t)105 * 86400;
|
||||
const int64_t about_1_year = (int64_t)365 * 86400;
|
||||
|
||||
int64_t get_seconds_since_epoch ();
|
||||
struct Instant {
|
||||
// Seconds since Unix epoch
|
||||
int64_t x;
|
||||
|
||||
Instant (int64_t x);
|
||||
static Instant now ();
|
||||
};
|
||||
|
||||
struct TimeRange {
|
||||
int64_t not_before;
|
||||
int64_t not_after;
|
||||
|
||||
bool contains (Instant x) const;
|
||||
int64_t duration () const;
|
||||
|
||||
static TimeRange from_start_and_dur (Instant start, int64_t dur);
|
||||
};
|
||||
|
||||
int test_time ();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue