Policy Engine¶
The central Zero Trust decision point. It combines identity-based authorization, certificate validation (delegating signature checks the same way zt-certificate does), revocation, and a micro-segmentation extension: role-to-role rules with time-of-day windows and rate limits, evaluated through IdentityRegistry and fingerprinted with ComputeSha256. Every decision that is not explicitly allowed defaults to DENY (least privilege).
Depends on: Identity Registry, Hash Utilities
Used in examples: Man-in-the-Middle: Attack & Mitigation, Identity Spoofing: Attack & Mitigation, Unauthorized Access: Attack & Mitigation, Context Drift Test, Micro-Segmentation Test
API summary¶
ZtPolicyEngine
| Member | Description |
|---|---|
AddAuthorized(nodeId, role) |
Registers a node/role pair as authorized. |
Authorize(nodeId, role) |
Simple identity-based authorization check. |
SetCaPublicKey(pub) |
Registers the CA public key for certificate-based checks. |
Revoke(nodeId) |
Revokes a node, blocking all further authorization for it. |
AuthorizeWithCert(nodeId, role, certStr) |
Certificate-based authorization (signature, identity, expiry, revocation). |
AddRolePolicyRule(rule) |
Adds a RolePolicyRule (src role, dst role, action, time window, rate limit, ALLOW/DENY) and bumps the policy version. |
EvaluateMicroSegmentation(srcNode, dstNode, action) |
Resolves roles via IdentityRegistry, matches rules, checks time window and rate limit, computes the Ψ fingerprint, and returns ALLOW/DENY. |
GetPolicyVersion() |
Returns how many rules have been added (a monotonically increasing version counter). |
GetPolicyIntegrityHash() |
Returns a SHA-256 fingerprint over the full rule set, for tamper detection. |
Header — zt-policy-engine.h¶
zt-policy-engine.h
#ifndef ZT_POLICY_ENGINE_H
#define ZT_POLICY_ENGINE_H
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <map>
#include <ns3/object.h>
#include <ns3/node.h>
#include <cryptopp/rsa.h>
using namespace CryptoPP;
namespace ns3 {
/**
* \ingroup zerotrust
* \brief Zero Trust Policy Engine with:
* - Identity-based authorization
* - Certificate validation
* - Revocation support
* - Micro-segmentation (custom extension)
*/
class ZtPolicyEngine : public Object
{
public:
static TypeId GetTypeId();
ZtPolicyEngine();
virtual ~ZtPolicyEngine();
/* =====================================================
EXISTING FUNCTIONALITY (DO NOT MODIFY)
===================================================== */
void AddAuthorized(uint32_t nodeId, const std::string& role);
bool Authorize(uint32_t nodeId, const std::string& role);
void SetCaPublicKey(RSA::PublicKey pub);
void Revoke(uint32_t nodeId);
bool AuthorizeWithCert(uint32_t nodeId,
const std::string& role,
const std::string& certStr);
/* =====================================================
NEW: MICRO-SEGMENTATION EXTENSION
===================================================== */
enum RuleEffect
{
ALLOW = 0,
DENY = 1
};
struct RolePolicyRule
{
std::string srcRole;
std::string dstRole;
std::string action;
uint32_t startHour;
uint32_t endHour;
uint32_t windowSeconds;
uint32_t maxTransfers;
RuleEffect effect;
};
void AddRolePolicyRule(const RolePolicyRule& rule);
bool EvaluateMicroSegmentation(
Ptr<Node> srcNode,
Ptr<Node> dstNode,
const std::string& action);
uint32_t GetPolicyVersion() const;
std::string GetPolicyIntegrityHash() const;
private:
/* ================= EXISTING ================= */
std::unordered_map<uint32_t, std::string> authTable;
std::unordered_set<uint32_t> revoke;
RSA::PublicKey caPublicKey;
/* ================= NEW ================= */
bool IsWithinTime(uint32_t startHour,
uint32_t endHour);
uint32_t GetBehaviorState(uint32_t nodeId,
uint32_t windowSeconds);
private:
/* ================= NEW STORAGE ================= */
std::vector<RolePolicyRule> m_rules;
std::map<uint32_t, std::vector<uint64_t>> m_transferHistory;
uint32_t m_policyVersion;
};
} // namespace ns3
#endif // ZT_POLICY_ENGINE_H
Implementation — zt-policy-engine.cc¶
zt-policy-engine.cc
// === zt-policy-engine.cc ===
#include "zt-policy-engine.h"
#include "zt-identity-registry.h"
#include "zt-hash-utils.h"
#include <ns3/log.h>
#include <sstream>
#include <ctime>
#include <algorithm>
#include <iostream>
// Crypto++
#include <cryptopp/base64.h>
#include <cryptopp/filters.h>
#include <cryptopp/pssr.h>
#include <cryptopp/sha.h>
namespace ns3 {
NS_LOG_COMPONENT_DEFINE("ZtPolicyEngine");
NS_OBJECT_ENSURE_REGISTERED(ZtPolicyEngine);
// ===================== TypeId =====================
TypeId ZtPolicyEngine::GetTypeId() {
static TypeId tid = TypeId("ZtPolicyEngine")
.SetParent<Object>()
.SetGroupName("ZeroTrust")
.AddConstructor<ZtPolicyEngine>();
return tid;
}
// ===================== Constructor =====================
ZtPolicyEngine::ZtPolicyEngine()
: m_policyVersion(0)
{
}
// ===================== Destructor (ADDED FIX) =====================
ZtPolicyEngine::~ZtPolicyEngine()
{
}
// ===================== BASIC AUTH =====================
void ZtPolicyEngine::AddAuthorized(uint32_t nodeId, const std::string& role) {
authTable[nodeId] = role;
}
bool ZtPolicyEngine::Authorize(uint32_t nodeId, const std::string& role) {
return authTable.find(nodeId) != authTable.end() &&
authTable[nodeId] == role;
}
// ===================== CERTIFICATE =====================
void ZtPolicyEngine::SetCaPublicKey(RSA::PublicKey pub) {
caPublicKey = pub;
}
void ZtPolicyEngine::Revoke(uint32_t nodeId) {
revoke.insert(nodeId);
}
bool ZtPolicyEngine::AuthorizeWithCert(uint32_t nodeId,
const std::string& role,
const std::string& certStr) {
if (revoke.find(nodeId) != revoke.end()) {
NS_LOG_UNCOND("ZT-CERT: Node " << nodeId << " is revoked");
return false;
}
std::string content, sig;
size_t sigPos = certStr.find("|SIG:");
if (sigPos == std::string::npos) return false;
content = certStr.substr(0, sigPos);
sig = certStr.substr(sigPos + 5);
std::string decodedSig;
CryptoPP::StringSource(sig, true,
new CryptoPP::Base64Decoder(
new CryptoPP::StringSink(decodedSig)));
CryptoPP::RSASS<CryptoPP::PSSR, CryptoPP::SHA1>::Verifier verifier(caPublicKey);
bool valid = false;
CryptoPP::StringSource(decodedSig + content, true,
new CryptoPP::SignatureVerificationFilter(
verifier,
new CryptoPP::ArraySink((byte*)&valid, sizeof(valid)),
CryptoPP::SignatureVerificationFilter::PUT_RESULT |
CryptoPP::SignatureVerificationFilter::SIGNATURE_AT_BEGIN));
if (!valid) {
NS_LOG_UNCOND("ZT-CERT: Signature invalid");
return false;
}
std::istringstream ss(content);
std::string token;
uint32_t idParsed = 0;
std::string roleParsed;
time_t expiry = 0;
while (std::getline(ss, token, '|')) {
if (token.find("ID:") == 0)
idParsed = std::stoul(token.substr(3));
else if (token.find("ROLE:") == 0)
roleParsed = token.substr(5);
else if (token.find("EXP:") == 0)
expiry = std::stol(token.substr(4));
}
if (idParsed != nodeId || roleParsed != role) {
NS_LOG_UNCOND("ZT-CERT: Identity mismatch");
return false;
}
if (std::time(nullptr) > expiry) {
NS_LOG_UNCOND("ZT-CERT: Certificate expired");
return false;
}
return true;
}
// ===================== MICRO-SEGMENTATION =====================
// Add rule
void ZtPolicyEngine::AddRolePolicyRule(const RolePolicyRule& rule) {
m_rules.push_back(rule);
m_policyVersion++;
std::cout << "[POLICY] Rule Added. Version: "
<< m_policyVersion << "\n";
}
// Time check
bool ZtPolicyEngine::IsWithinTime(uint32_t startHour,
uint32_t endHour) {
std::time_t now = std::time(nullptr);
std::tm* local = std::localtime(&now);
uint32_t hour = local->tm_hour;
return (hour >= startHour && hour < endHour);
}
// Behavior tracking
uint32_t ZtPolicyEngine::GetBehaviorState(uint32_t nodeId,
uint32_t windowSeconds) {
uint64_t now = std::time(nullptr);
auto& history = m_transferHistory[nodeId];
history.erase(
std::remove_if(history.begin(), history.end(),
[&](uint64_t t) { return now - t > windowSeconds; }),
history.end());
return history.size();
}
// Core evaluation
bool ZtPolicyEngine::EvaluateMicroSegmentation(
Ptr<Node> srcNode,
Ptr<Node> dstNode,
const std::string& action) {
if (!srcNode || !dstNode) {
std::cout << "[MICRO-SEG] Invalid Node Pointer\n";
return false;
}
IdentityRegistry& registry =
IdentityRegistry::GetInstance();
std::string Hs = registry.GetIdentityHash(srcNode);
std::string Hd = registry.GetIdentityHash(dstNode);
std::string srcRole = registry.GetRole(srcNode);
std::string dstRole = registry.GetRole(dstNode);
uint32_t nodeId = srcNode->GetId();
std::time_t now = std::time(nullptr);
std::tm* local = std::localtime(&now);
uint32_t currentHour = local->tm_hour;
for (const auto& rule : m_rules) {
if (rule.srcRole == srcRole &&
rule.dstRole == dstRole &&
(rule.action == action || rule.action == "*")) {
if (!IsWithinTime(rule.startHour, rule.endHour))
continue;
uint32_t transferCount =
GetBehaviorState(nodeId, rule.windowSeconds);
uint32_t behaviorState =
(transferCount <= rule.maxTransfers) ? 0 : 1;
std::string S =
Hs + Hd +
action +
std::to_string(currentHour) +
rule.srcRole +
rule.dstRole +
std::to_string(behaviorState);
std::string Psi = ns3::ComputeSha256(S);
std::cout << "[MICRO-SEG] Ψ: " << Psi << "\n";
if (behaviorState == 0 &&
rule.effect == ALLOW) {
if (action == "TRANSFER" || action == "WITHDRAW") {
m_transferHistory[nodeId].push_back(now);
}
return true;
}
if (rule.effect == DENY) {
return false;
}
}
}
std::cout << "[MICRO-SEG] Default DENY (Least Privilege)\n";
return false;
}
// ===================== POLICY INTEGRITY =====================
uint32_t ZtPolicyEngine::GetPolicyVersion() const {
return m_policyVersion;
}
std::string ZtPolicyEngine::GetPolicyIntegrityHash() const {
std::stringstream ss;
ss << m_policyVersion;
for (const auto& rule : m_rules) {
ss << rule.srcRole
<< rule.dstRole
<< rule.action
<< rule.startHour
<< rule.endHour
<< rule.windowSeconds
<< rule.maxTransfers
<< rule.effect;
}
return ns3::ComputeSha256(ss.str());
}
} // namespace ns3