2021-01-18 00:00:45 +00:00
|
|
|
#include "receiver.h"
|
|
|
|
|
|
|
|
#include <sodium.h>
|
|
|
|
|
|
|
|
#include "json.hpp"
|
|
|
|
|
|
|
|
#include "expiring_signature.h"
|
|
|
|
#include "sodium_helpers.h"
|
|
|
|
#include "string_helpers.h"
|
|
|
|
#include "time_helpers.h"
|
|
|
|
|
|
|
|
namespace BareMinimumCrypto::Receiver {
|
|
|
|
using nlohmann::json;
|
|
|
|
|
2021-01-20 01:31:41 +00:00
|
|
|
bool is_pubkey_length (const Bytes & v) {
|
2021-01-18 00:00:45 +00:00
|
|
|
return v.size () == crypto_sign_PUBLICKEYBYTES;
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:31:41 +00:00
|
|
|
optional <Bytes> try_verify_signed_data (
|
|
|
|
const Bytes & pubkey,
|
2021-01-18 01:17:06 +00:00
|
|
|
const ExpiringSignature & sig,
|
2021-01-18 00:00:45 +00:00
|
|
|
Instant now
|
|
|
|
) {
|
|
|
|
try_sodium_init ();
|
|
|
|
|
|
|
|
if (! is_pubkey_length (pubkey)) {
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (crypto_sign_verify_detached (
|
|
|
|
sig.sig.data (),
|
2021-01-18 22:13:48 +00:00
|
|
|
sig.cert.data (),
|
|
|
|
sig.cert.size (),
|
2021-01-18 00:00:45 +00:00
|
|
|
pubkey.data ()
|
|
|
|
) != 0) {
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2021-01-18 22:13:48 +00:00
|
|
|
const json j = json::from_msgpack (sig.cert);
|
2021-01-18 00:00:45 +00:00
|
|
|
|
|
|
|
const TimeRange tr {
|
|
|
|
j ["not_before"],
|
|
|
|
j ["not_after"]
|
|
|
|
};
|
|
|
|
|
|
|
|
if (! tr.contains (now)) {
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
|
2021-01-18 22:23:38 +00:00
|
|
|
const auto payload = j ["payload"].get_binary ();
|
2021-01-18 00:00:45 +00:00
|
|
|
|
|
|
|
return payload;
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:31:41 +00:00
|
|
|
optional <Bytes> verify_signed_data (
|
|
|
|
const Bytes & pubkey,
|
2021-01-18 01:17:06 +00:00
|
|
|
const ExpiringSignature & sig,
|
2021-01-18 00:00:45 +00:00
|
|
|
Instant now
|
|
|
|
) {
|
|
|
|
try {
|
2021-01-18 01:17:06 +00:00
|
|
|
return try_verify_signed_data (pubkey, sig, now);
|
2021-01-18 00:00:45 +00:00
|
|
|
}
|
|
|
|
catch (json::exception &) {
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:31:41 +00:00
|
|
|
optional <Bytes> try_verify_cert_and_data (
|
|
|
|
const Bytes & root_pubkey,
|
|
|
|
const Bytes & msgpack,
|
2021-01-18 01:17:06 +00:00
|
|
|
Instant now
|
|
|
|
) {
|
2021-01-18 22:13:48 +00:00
|
|
|
const auto j = json::from_msgpack (msgpack);
|
2021-01-18 01:17:06 +00:00
|
|
|
|
|
|
|
ExpiringSignature cert;
|
|
|
|
|
2021-01-18 22:13:48 +00:00
|
|
|
cert.sig = j ["cert"]["sig"].get_binary ();
|
|
|
|
cert.cert = j ["cert"]["cert"].get_binary ();
|
2021-01-18 01:17:06 +00:00
|
|
|
|
|
|
|
auto subkey_opt = verify_signed_data (root_pubkey, cert, now);
|
2021-01-18 22:23:38 +00:00
|
|
|
|
|
|
|
const auto subkey_obj = json::from_msgpack (std::move (*subkey_opt));
|
|
|
|
const auto subkey = subkey_obj ["key"].get_binary ();
|
2021-01-18 01:17:06 +00:00
|
|
|
|
|
|
|
ExpiringSignature data;
|
|
|
|
|
2021-01-18 22:13:48 +00:00
|
|
|
data.sig = j ["data"]["sig"].get_binary ();
|
|
|
|
data.cert = j ["data"]["cert"].get_binary ();
|
2021-01-18 01:17:06 +00:00
|
|
|
|
|
|
|
return verify_signed_data (subkey, data, now);
|
|
|
|
}
|
|
|
|
|
2021-01-20 01:31:41 +00:00
|
|
|
optional <Bytes> verify_cert_and_data (
|
|
|
|
const Bytes & root_pubkey,
|
|
|
|
const Bytes & msgpack
|
2021-01-18 01:17:06 +00:00
|
|
|
) {
|
|
|
|
try {
|
2021-01-18 22:13:48 +00:00
|
|
|
return try_verify_cert_and_data (root_pubkey, msgpack, Instant::now ());
|
2021-01-18 01:17:06 +00:00
|
|
|
}
|
|
|
|
catch (json::exception &) {
|
|
|
|
return nullopt;
|
|
|
|
}
|
|
|
|
}
|
2021-01-18 00:00:45 +00:00
|
|
|
}
|