Certificate Authority & Certificate-Based Policy¶
Simulates a lightweight X.509-style Certificate Authority (CA) for the Zero Trust fabric. CertificateAuthority generates an RSA key pair and signs identity certificates that bind a node ID, role, and expiry time. ZtPolicyEngineWithCert is a companion policy engine that verifies those signatures, checks expiry, and honours a revocation list before granting access — a certificate-only alternative to the main ZtPolicyEngine.
Used in examples: Man-in-the-Middle: Attack & Mitigation, Identity Spoofing: Attack & Mitigation, Unauthorized Access: Attack & Mitigation
API summary¶
CertificateAuthority
| Member | Description |
|---|---|
CertificateAuthority() |
Generates a fresh 1024-bit RSA key pair for the CA. |
SignIdentity(nodeId, role, expiry) |
Signs ID:.. | ROLE:.. | EXP:.. and returns the certificate string with a base64-encoded RSA-PSS signature. |
GetPublicKey() |
Returns the CA's public key so it can be distributed to verifiers. |
ZtPolicyEngineWithCert
| Member | Description |
|---|---|
SetCaPublicKey(pub) |
Registers the trusted CA public key used for signature verification. |
Revoke(nodeId) |
Adds a node ID to the revocation set. |
Authorize(nodeId, role, certStr) |
Verifies the signature, checks node ID/role match, expiry, and revocation status. |
Header — zt-certificate.h¶
zt-certificate.h
#ifndef ZT_CERTIFICATE_H
#define ZT_CERTIFICATE_H
#include <string>
#include <ctime>
#include <unordered_set>
#include <cryptopp/rsa.h>
#include <cryptopp/base64.h>
/**
* \class CertificateAuthority
* \brief Simulates a Certificate Authority (CA) that issues and signs identity certificates.
*
* The CA generates a public-private RSA key pair and uses it to sign certificates
* for nodes, which include identity, role, and expiry information.
*/
class CertificateAuthority {
public:
/**
* \brief Constructor that initializes and generates RSA key pair.
*/
CertificateAuthority();
/**
* \brief Signs an identity certificate with node ID, role, and expiry.
* \param nodeId The unique identifier of the node.
* \param role The assigned role of the node (e.g., "sensor", "gateway").
* \param expiry Expiry timestamp for the certificate.
* \return A signed certificate string in plain format with a base64-encoded signature.
*/
std::string SignIdentity(uint32_t nodeId, const std::string& role, time_t expiry);
/**
* \brief Retrieves the public RSA key of the CA.
* \return The public key corresponding to the CA's private key.
*/
CryptoPP::RSA::PublicKey GetPublicKey() const;
private:
CryptoPP::RSA::PrivateKey privateKey; ///< RSA private key used for signing certificates.
CryptoPP::RSA::PublicKey publicKey; ///< RSA public key distributed for verification.
};
/**
* \class ZtPolicyEngineWithCert
* \brief Simulates a Zero Trust policy engine that enforces access control using certificates.
*
* This engine validates node certificates, verifies digital signatures, checks role and expiry,
* and maintains a list of revoked node IDs.
*/
class ZtPolicyEngineWithCert {
public:
/**
* \brief Sets the CA's public key used for certificate verification.
* \param pub The public RSA key of the trusted Certificate Authority.
*/
void SetCaPublicKey(CryptoPP::RSA::PublicKey pub);
/**
* \brief Revokes a node by its ID, preventing it from being authorized.
* \param nodeId The node ID to be added to the revocation list.
*/
void Revoke(uint32_t nodeId);
/**
* \brief Authorizes a node based on its certificate.
* \param nodeId The node's claimed ID.
* \param role The role the node claims to perform.
* \param certStr The certificate string presented by the node.
* \return True if the certificate is valid, not expired, matches the node, and not revoked.
*/
bool Authorize(uint32_t nodeId, const std::string& role, const std::string& certStr);
private:
CryptoPP::RSA::PublicKey caPublicKey; ///< Trusted public key used for signature verification.
std::unordered_set<uint32_t> revoke; ///< Set of node IDs that are explicitly revoked.
};
#endif // ZT_CERTIFICATE_H
Implementation — zt-certificate.cc¶
zt-certificate.cc
#include "zt-certificate.h"
#include <cryptopp/osrng.h>
#include <cryptopp/pssr.h>
#include <cryptopp/sha.h>
#include <cryptopp/filters.h>
#include <cryptopp/files.h>
#include <sstream>
#include <ns3/core-module.h>
using namespace CryptoPP;
/**
* \class CertificateAuthority
* \brief Issues and signs certificates for Zero Trust identity validation.
*/
CertificateAuthority::CertificateAuthority() {
AutoSeededRandomPool prng;
privateKey.GenerateRandomWithKeySize(prng, 1024);
publicKey = privateKey;
}
/**
* \brief Signs a certificate with node ID, role, and expiry.
* \param nodeId ID of the node requesting certificate
* \param role Role assigned to the node (e.g., sensor, gateway)
* \param expiry Expiry timestamp of the certificate
* \return Signed certificate string with base64-encoded signature
*/
std::string CertificateAuthority::SignIdentity(uint32_t nodeId, const std::string& role, time_t expiry) {
AutoSeededRandomPool prng;
std::ostringstream cert;
cert << "ID:" << nodeId << "|ROLE:" << role << "|EXP:" << expiry;
RSASS<PSSR, SHA1>::Signer signer(privateKey);
std::string signature;
StringSource(cert.str(), true,
new SignerFilter(prng, signer,
new StringSink(signature)));
std::string encodedSig;
StringSource(signature, true,
new Base64Encoder(new StringSink(encodedSig), false));
return cert.str() + "|SIG:" + encodedSig;
}
/**
* \brief Returns the public key of the Certificate Authority.
* \return RSA public key
*/
RSA::PublicKey CertificateAuthority::GetPublicKey() const {
return publicKey;
}
/**
* \brief Sets the CA public key for the policy engine.
* \param pub RSA public key of the certificate authority
*/
void ZtPolicyEngineWithCert::SetCaPublicKey(RSA::PublicKey pub) {
caPublicKey = pub;
}
/**
* \brief Revokes access for a specific node.
* \param nodeId ID of the node to be revoked
*/
void ZtPolicyEngineWithCert::Revoke(uint32_t nodeId) {
revoke.insert(nodeId);
}
/**
* \brief Verifies and authorizes a node based on its certificate.
* \param nodeId ID of the node attempting access
* \param role Role of the node
* \param certStr Certificate string to validate
* \return True if the certificate is valid and authorization succeeds
*/
bool ZtPolicyEngineWithCert::Authorize(uint32_t nodeId, const std::string& role, const std::string& certStr) {
using namespace ns3;
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;
StringSource(sig, true, new Base64Decoder(new StringSink(decodedSig)));
RSASS<PSSR, SHA1>::Verifier verifier(caPublicKey);
bool valid = false;
StringSource(decodedSig + content, true,
new SignatureVerificationFilter(verifier,
new ArraySink((byte*)&valid, sizeof(valid)),
SignatureVerificationFilter::PUT_RESULT | 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;
}
time_t now = std::time(nullptr);
if (now > expiry) {
NS_LOG_UNCOND("ZT-CERT: Certificate expired");
return false;
}
return true;
}