Add packaged DLP broker and protected Windows service foundation
This commit is contained in:
1 parent
95d23f4e0b
commit
7b5057901a
140 files changed
+11215
-60
No files matched your search
@@ -0,0 +1,114 @@
|
||||
#pragma once
|
||||
#include "signed-manifest.h"
|
||||
// Canonical monotonic state contract. No registry operations in this header.
|
||||
namespace acceptance_contract {
|
||||
using release_contract::Json;
|
||||
static bool sha(const std::string &value) {
|
||||
if (value.size() != 64)
|
||||
return false;
|
||||
for (char c : value)
|
||||
if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
static bool userSid(const std::string &value) {
|
||||
if ((value.rfind("S-1-5-21-", 0) != 0 && value.rfind("S-1-12-1-", 0) != 0) ||
|
||||
std::count(value.begin(), value.end(), '-') != 7)
|
||||
return false;
|
||||
PSID sid = nullptr;
|
||||
if (!ConvertStringSidToSidA(value.c_str(), &sid))
|
||||
return false;
|
||||
LPSTR text = nullptr;
|
||||
bool valid = ConvertSidToStringSidA(sid, &text) && text && value == text;
|
||||
if (text)
|
||||
LocalFree(text);
|
||||
LocalFree(sid);
|
||||
return valid;
|
||||
}
|
||||
static std::string identity(const Json &record) {
|
||||
return release_contract::str(record.object.at("sid")) + "|" +
|
||||
release_contract::str(record.object.at("deviceId")) + "|" +
|
||||
release_contract::str(record.object.at("policyKeySha256"));
|
||||
}
|
||||
static void floor(const Json &value, bool deployment) {
|
||||
if (!release_contract::exact(
|
||||
value,
|
||||
deployment
|
||||
? std::initializer_list<const char *>{"minimumSequence",
|
||||
"acceptedDigest", "tenant"}
|
||||
: std::initializer_list<const char *>{"minimumSequence",
|
||||
"acceptedDigest"}) ||
|
||||
!sha(release_contract::str(value.object.at("acceptedDigest"))) ||
|
||||
!release_contract::number(value.object.at("minimumSequence")) ||
|
||||
(deployment && !release_contract::uuid(
|
||||
release_contract::str(value.object.at("tenant")))))
|
||||
throw std::runtime_error("fixed-state-invalid");
|
||||
}
|
||||
static Json validate(const std::string &text) {
|
||||
if (text.size() > 2096128)
|
||||
throw std::runtime_error("fixed-state-invalid");
|
||||
Json state = release_contract::json(text);
|
||||
if (!release_contract::exact(
|
||||
state, {"format", "release", "deployment", "policies"}) ||
|
||||
release_contract::str(state.object.at("format")) !=
|
||||
"safetynet-service-floors-v1")
|
||||
throw std::runtime_error("fixed-state-invalid");
|
||||
floor(state.object.at("release"), false);
|
||||
floor(state.object.at("deployment"), true);
|
||||
const auto &policies = state.object.at("policies");
|
||||
if (policies.kind != Json::Array || policies.array.size() > 8192)
|
||||
throw std::runtime_error("fixed-state-invalid");
|
||||
std::string previous;
|
||||
for (const auto &record : policies.array) {
|
||||
if (!release_contract::exact(record,
|
||||
{"sid", "deviceId", "policyKeySha256",
|
||||
"minimumVersion", "acceptedDigest"}) ||
|
||||
!userSid(release_contract::str(record.object.at("sid"))) ||
|
||||
!sha(release_contract::str(record.object.at("policyKeySha256"))) ||
|
||||
!sha(release_contract::str(record.object.at("acceptedDigest"))) ||
|
||||
!release_contract::number(record.object.at("minimumVersion")))
|
||||
throw std::runtime_error("fixed-state-invalid");
|
||||
auto device = release_contract::str(record.object.at("deviceId"));
|
||||
if (device.empty() || device.size() > 80 ||
|
||||
!isalnum(static_cast<unsigned char>(device[0])))
|
||||
throw std::runtime_error("fixed-state-invalid");
|
||||
for (unsigned char c : device)
|
||||
if (!isalnum(c) && c != '.' && c != '_' && c != '-')
|
||||
throw std::runtime_error("fixed-state-invalid");
|
||||
auto id = identity(record);
|
||||
if (!previous.empty() && id <= previous)
|
||||
throw std::runtime_error("fixed-state-invalid");
|
||||
previous = id;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
static bool nondecreasing(const Json &previous, const Json &candidate,
|
||||
const char *field) {
|
||||
auto old = release_contract::number(previous.object.at(field)),
|
||||
next = release_contract::number(candidate.object.at(field));
|
||||
return next >= old &&
|
||||
(next != old ||
|
||||
release_contract::str(previous.object.at("acceptedDigest")) ==
|
||||
release_contract::str(candidate.object.at("acceptedDigest")));
|
||||
}
|
||||
static bool transition(const Json &old, const Json &candidate) {
|
||||
if (!nondecreasing(old.object.at("release"), candidate.object.at("release"),
|
||||
"minimumSequence") ||
|
||||
!nondecreasing(old.object.at("deployment"),
|
||||
candidate.object.at("deployment"), "minimumSequence") ||
|
||||
release_contract::str(old.object.at("deployment").object.at("tenant")) !=
|
||||
release_contract::str(
|
||||
candidate.object.at("deployment").object.at("tenant")))
|
||||
return false;
|
||||
std::map<std::string, const Json *> records;
|
||||
for (const auto &record : candidate.object.at("policies").array)
|
||||
records.emplace(identity(record), &record);
|
||||
for (const auto &record : old.object.at("policies").array) {
|
||||
auto match = records.find(identity(record));
|
||||
if (match == records.end() ||
|
||||
!nondecreasing(record, *match->second, "minimumVersion"))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace acceptance_contract
|
||||
Reference in new issue
Block a user