Update the NDNCERT library to version NDNCERT v2
spec:[https://github.com/named-data/ndncert/wiki/NDNCERT-Protocol-new]
Change-Id: Ia480a8e70c4b38ca170dfe2fcf50d1265ab65f46
diff --git a/src/ca-config.cpp b/src/ca-config.cpp
index 06b5c68..b8b0d59 100644
--- a/src/ca-config.cpp
+++ b/src/ca-config.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -40,41 +40,24 @@
if (configJson.begin() == configJson.end()) {
BOOST_THROW_EXCEPTION(Error("Error processing configuration file: " + fileName + " no data"));
}
-
parse(configJson);
}
void
CaConfig::parse(const JsonSection& configJson)
{
- m_caItems.clear();
- auto caList = configJson.get_child("ca-list");
- auto it = caList.begin();
- for (; it != caList.end(); it++) {
- CaItem item;
-
// essential info
- item.m_caName = Name(it->second.get<std::string>("ca-prefix"));
- item.m_freshnessPeriod = time::seconds(it->second.get("issuing-freshness", 720));
- item.m_validityPeriod = time::days(it->second.get("validity-period", 360));
+ m_caName = Name(configJson.get<std::string>("ca-prefix"));
+ m_freshnessPeriod = time::seconds(configJson.get("issuing-freshness", 720));
+ m_validityPeriod = time::days(configJson.get("max-validity-period", 360));
// optional info
- item.m_probe = it->second.get("probe", "");
- item.m_caInfo = it->second.get("ca-info", "");
- item.m_targetedList = it->second.get("targeted-list", "");
+ m_probe = configJson.get("probe", "");
+ m_caInfo = configJson.get("ca-info", "");
// optional supported challenges
- auto challengeList = it->second.get_child("supported-challenges");
- item.m_supportedChallenges = parseChallengeList(challengeList);
-
- // related cas
- auto relatedCaList = it->second.get_child_optional("related-ca-list");
- if (relatedCaList) {
- item.m_relatedCaList = parseRelatedCaList(*relatedCaList);
- }
-
- m_caItems.push_back(item);
- }
+ auto challengeList = configJson.get_child("supported-challenges");
+ m_supportedChallenges = parseChallengeList(challengeList);
}
std::list<std::string>
@@ -88,17 +71,5 @@
return result;
}
-std::list<Name>
-CaConfig::parseRelatedCaList(const JsonSection& section)
-{
- std::list<Name> result;
- auto it = section.begin();
- for (; it != section.end(); it++) {
- Name item(it->second.get<std::string>("ca-prefix"));
- result.push_back(item);
- }
- return result;
-}
-
} // namespace ndncert
} // namespace ndn
diff --git a/src/ca-config.hpp b/src/ca-config.hpp
index a0e66ae..83bd821 100644
--- a/src/ca-config.hpp
+++ b/src/ca-config.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -36,16 +36,6 @@
using ProbeHandler = function<std::string/*identity name*/ (const std::string&/*requester input*/)>;
/**
- * @brief The function should recommend a CA plus an identity name from the given list
- * based on LIST additional info
- *
- * The function should throw exceptions when there is an unexpected input.
- */
-using RecommendCaHandler = function<std::tuple<Name/*CA name*/, std::string/*identity*/>
- (const std::string&/*requester input*/,
- const std::list<Name>&/*related CA list*/)>;
-
-/**
* @brief The function would be invoked whenever the certificate request status gets update
*
* The callback is used to notice the CA application or CA command line tool. The callback is
@@ -54,31 +44,6 @@
*/
using StatusUpdateCallback = function<void (const CertificateRequest&/*the latest request info*/)>;
-class CaItem
-{
-public:
- // basic info
- Name m_caName;
-
- // related CAs
- std::list<Name> m_relatedCaList;
-
- // essential config
- time::seconds m_freshnessPeriod;
- time::days m_validityPeriod;
- std::list<std::string> m_supportedChallenges;
-
- // optional parameters
- std::string m_probe;
- std::string m_targetedList;
- std::string m_caInfo;
-
- // callbacks
- ProbeHandler m_probeHandler;
- RecommendCaHandler m_recommendCaHandler;
- StatusUpdateCallback m_statusUpdateCallback;
-};
-
/**
* @brief Represents a CA configuration instance
*
@@ -110,11 +75,22 @@
std::list<std::string>
parseChallengeList(const JsonSection& configSection);
- std::list<Name>
- parseRelatedCaList(const JsonSection& section);
-
public:
- std::list<CaItem> m_caItems;
+ // basic info
+ Name m_caName;
+
+ // essential config
+ time::seconds m_freshnessPeriod;
+ time::days m_validityPeriod;
+ std::list<std::string> m_supportedChallenges;
+
+ // optional parameters
+ std::string m_probe;
+ std::string m_caInfo;
+
+ // callbacks
+ ProbeHandler m_probeHandler;
+ StatusUpdateCallback m_statusUpdateCallback;
};
} // namespace ndncert
diff --git a/src/ca-detail/ca-memory.cpp b/src/ca-detail/ca-memory.cpp
index 566e08c..ce5bd98 100644
--- a/src/ca-detail/ca-memory.cpp
+++ b/src/ca-detail/ca-memory.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -43,32 +43,32 @@
{
for (auto& entry : m_requests) {
const auto& existingRequest = entry.second;
- if (existingRequest.getCert().getKeyName() == request.getCert().getKeyName()) {
- BOOST_THROW_EXCEPTION(Error("Request for " + request.getCert().getKeyName().toUri() + " already exists"));
+ if (existingRequest.m_cert.getKeyName() == request.m_cert.getKeyName()) {
+ BOOST_THROW_EXCEPTION(Error("Request for " + request.m_cert.getKeyName().toUri() + " already exists"));
return;
}
}
for (auto& entry : m_issuedCerts) {
const auto& cert = entry.second;
- if (cert.getKeyName() == request.getCert().getKeyName()) {
- BOOST_THROW_EXCEPTION(Error("Cert for " + request.getCert().getKeyName().toUri() + " already exists"));
+ if (cert.getKeyName() == request.m_cert.getKeyName()) {
+ BOOST_THROW_EXCEPTION(Error("Cert for " + request.m_cert.getKeyName().toUri() + " already exists"));
return;
}
}
- auto search = m_requests.find(request.getRequestId());
+ auto search = m_requests.find(request.m_requestId);
if (search == m_requests.end()) {
- m_requests[request.getRequestId()] = request;
+ m_requests[request.m_requestId] = request;
}
else {
- BOOST_THROW_EXCEPTION(Error("Request " + request.getRequestId() + " already exists"));
+ BOOST_THROW_EXCEPTION(Error("Request " + request.m_requestId + " already exists"));
}
}
void
CaMemory::updateRequest(const CertificateRequest& request)
{
- m_requests[request.getRequestId()] = request;
+ m_requests[request.m_requestId] = request;
}
void
@@ -95,7 +95,7 @@
{
std::list<CertificateRequest> result;
for (const auto& entry : m_requests) {
- if (entry.second.getCaName() == caName) {
+ if (entry.second.m_caName == caName) {
result.push_back(entry.second);
}
}
diff --git a/src/ca-detail/ca-sqlite.cpp b/src/ca-detail/ca-sqlite.cpp
index 34f5d19..bb88cc7 100644
--- a/src/ca-detail/ca-sqlite.cpp
+++ b/src/ca-detail/ca-sqlite.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -40,11 +40,15 @@
id INTEGER PRIMARY KEY,
request_id TEXT NOT NULL,
ca_name BLOB NOT NULL,
- status TEXT NOT NULL,
+ status INTEGER NOT NULL,
+ challenge_status TEXT,
cert_key_name BLOB NOT NULL,
cert_request BLOB NOT NULL,
challenge_type TEXT,
- challenge_secrets TEXT
+ challenge_secrets TEXT,
+ challenge_tp TEXT,
+ remaining_tries INTEGER,
+ remaining_time INTEGER
);
CREATE UNIQUE INDEX IF NOT EXISTS
CertRequestIdIndex ON CertRequests(request_id);
@@ -117,11 +121,17 @@
if (statement.step() == SQLITE_ROW) {
Name caName(statement.getBlock(2));
- std::string status = statement.getString(3);
- security::v2::Certificate cert(statement.getBlock(5));
- std::string challengeType = statement.getString(6);
- std::string challengeSecrets = statement.getString(7);
- return CertificateRequest(caName, requestId, status, challengeType, challengeSecrets, cert);
+ int status = statement.getInt(3);
+ std::string challengeStatus = statement.getString(4);
+ security::v2::Certificate cert(statement.getBlock(6));
+ std::string challengeType = statement.getString(7);
+ std::string challengeSecrets = statement.getString(8);
+ std::string challengeTp = statement.getString(9);
+ int remainingTries = statement.getInt(10);
+ int remainingTime = statement.getInt(11);
+ return CertificateRequest(caName, requestId, status, challengeStatus, challengeType,
+ challengeTp, remainingTime, remainingTries,
+ convertString2Json(challengeSecrets), cert);
}
else {
BOOST_THROW_EXCEPTION(Error("Request " + requestId + " cannot be fetched from database"));
@@ -132,35 +142,40 @@
CaSqlite::addRequest(const CertificateRequest& request)
{
Sqlite3Statement statement1(m_database,
- R"_SQLTEXT_(SELECT * FROM CertRequests where cert_key_name = ?)_SQLTEXT_");
- statement1.bind(1, request.getCert().getKeyName().wireEncode(), SQLITE_TRANSIENT);
+ R"_SQLTEXT_(SELECT * FROM CertRequests where cert_key_name = ?)_SQLTEXT_");
+ statement1.bind(1, request.m_cert.getKeyName().wireEncode(), SQLITE_TRANSIENT);
if (statement1.step() == SQLITE_ROW) {
- BOOST_THROW_EXCEPTION(Error("Request for " + request.getCert().getKeyName().toUri() + " already exists"));
+ BOOST_THROW_EXCEPTION(Error("Request for " + request.m_cert.getKeyName().toUri() + " already exists"));
return;
}
Sqlite3Statement statement2(m_database,
- R"_SQLTEXT_(SELECT * FROM IssuedCerts where cert_key_name = ?)_SQLTEXT_");
- statement2.bind(1, request.getCert().getKeyName().wireEncode(), SQLITE_TRANSIENT);
+ R"_SQLTEXT_(SELECT * FROM IssuedCerts where cert_key_name = ?)_SQLTEXT_");
+ statement2.bind(1, request.m_cert.getKeyName().wireEncode(), SQLITE_TRANSIENT);
if (statement2.step() == SQLITE_ROW) {
- BOOST_THROW_EXCEPTION(Error("Cert for " + request.getCert().getKeyName().toUri() + " already exists"));
+ BOOST_THROW_EXCEPTION(Error("Cert for " + request.m_cert.getKeyName().toUri() + " already exists"));
return;
}
Sqlite3Statement statement(m_database,
R"_SQLTEXT_(INSERT INTO CertRequests (request_id, ca_name, status,
- cert_key_name, cert_request, challenge_type, challenge_secrets)
- values (?, ?, ?, ?, ?, ?, ?))_SQLTEXT_");
- statement.bind(1, request.getRequestId(), SQLITE_TRANSIENT);
- statement.bind(2, request.getCaName().wireEncode(), SQLITE_TRANSIENT);
- statement.bind(3, request.getStatus(), SQLITE_TRANSIENT);
- statement.bind(4, request.getCert().getKeyName().wireEncode(), SQLITE_TRANSIENT);
- statement.bind(5, request.getCert().wireEncode(), SQLITE_TRANSIENT);
- statement.bind(6, request.getChallengeType(), SQLITE_TRANSIENT);
- statement.bind(7, convertJson2String(request.getChallengeSecrets()), SQLITE_TRANSIENT);
+ challenge_status, cert_key_name, cert_request, challenge_type, challenge_secrets,
+ challenge_tp, remaining_tries, remaining_time)
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?))_SQLTEXT_");
+ statement.bind(1, request.m_requestId, SQLITE_TRANSIENT);
+ statement.bind(2, request.m_caName.wireEncode(), SQLITE_TRANSIENT);
+ statement.bind(3, request.m_status);
+ statement.bind(4, request.m_challengeStatus, SQLITE_TRANSIENT);
+ statement.bind(5, request.m_cert.getKeyName().wireEncode(), SQLITE_TRANSIENT);
+ statement.bind(6, request.m_cert.wireEncode(), SQLITE_TRANSIENT);
+ statement.bind(7, request.m_challengeType, SQLITE_TRANSIENT);
+ statement.bind(8, convertJson2String(request.m_challengeSecrets), SQLITE_TRANSIENT);
+ statement.bind(9, request.m_challengeTp, SQLITE_TRANSIENT);
+ statement.bind(10, request.m_remainingTries);
+ statement.bind(11, request.m_remainingTime);
if (statement.step() != SQLITE_DONE) {
- BOOST_THROW_EXCEPTION(Error("Request " + request.getRequestId() + " cannot be added to database"));
+ BOOST_THROW_EXCEPTION(Error("Request " + request.m_requestId + " cannot be added to database"));
}
}
@@ -169,12 +184,17 @@
{
Sqlite3Statement statement(m_database,
R"_SQLTEXT_(UPDATE CertRequests
- SET status = ?, challenge_type = ?, challenge_secrets = ?
+ SET status = ?, challenge_status = ?, challenge_type = ?, challenge_secrets = ?,
+ challenge_tp = ?, remaining_tries = ?, remaining_time = ?
WHERE request_id = ?)_SQLTEXT_");
- statement.bind(1, request.getStatus(), SQLITE_TRANSIENT);
- statement.bind(2, request.getChallengeType(), SQLITE_TRANSIENT);
- statement.bind(3, convertJson2String(request.getChallengeSecrets()), SQLITE_TRANSIENT);
- statement.bind(4, request.getRequestId(), SQLITE_TRANSIENT);
+ statement.bind(1, request.m_status);
+ statement.bind(2, request.m_challengeStatus, SQLITE_TRANSIENT);
+ statement.bind(3, request.m_challengeType, SQLITE_TRANSIENT);
+ statement.bind(4, convertJson2String(request.m_challengeSecrets), SQLITE_TRANSIENT);
+ statement.bind(5, request.m_challengeTp, SQLITE_TRANSIENT);
+ statement.bind(6, request.m_remainingTries);
+ statement.bind(7, request.m_remainingTime);
+ statement.bind(8, request.m_requestId, SQLITE_TRANSIENT);
if (statement.step() != SQLITE_DONE) {
addRequest(request);
@@ -190,11 +210,17 @@
while(statement.step() == SQLITE_ROW) {
std::string requestId = statement.getString(1);
Name caName(statement.getBlock(2));
- std::string status = statement.getString(3);
- security::v2::Certificate cert(statement.getBlock(5));
- std::string challengeType = statement.getString(6);
- std::string challengeSecrets = statement.getString(7);
- CertificateRequest entry(caName, requestId, status, challengeType, challengeSecrets, cert);
+ int status = statement.getInt(3);
+ std::string challengeStatus = statement.getString(4);
+ security::v2::Certificate cert(statement.getBlock(6));
+ std::string challengeType = statement.getString(7);
+ std::string challengeSecrets = statement.getString(8);
+ std::string challengeTp = statement.getString(9);
+ int remainingTries = statement.getInt(10);
+ int remainingTime = statement.getInt(11);
+ CertificateRequest entry(caName, requestId, status, challengeStatus, challengeType,
+ challengeTp, remainingTime, remainingTries,
+ convertString2Json(challengeSecrets), cert);
result.push_back(entry);
}
return result;
@@ -210,11 +236,18 @@
while(statement.step() == SQLITE_ROW) {
std::string requestId = statement.getString(1);
- std::string status = statement.getString(3);
- security::v2::Certificate cert(statement.getBlock(5));
- std::string challengeType = statement.getString(6);
- std::string challengeSecrets = statement.getString(7);
- CertificateRequest entry(caName, requestId, status, challengeType, challengeSecrets, cert);
+ Name caName(statement.getBlock(2));
+ int status = statement.getInt(3);
+ std::string challengeStatus = statement.getString(4);
+ security::v2::Certificate cert(statement.getBlock(6));
+ std::string challengeType = statement.getString(7);
+ std::string challengeSecrets = statement.getString(8);
+ std::string challengeTp = statement.getString(9);
+ int remainingTries = statement.getInt(10);
+ int remainingTime = statement.getInt(11);
+ CertificateRequest entry(caName, requestId, status, challengeStatus, challengeType,
+ challengeTp, remainingTime, remainingTries,
+ convertString2Json(challengeSecrets), cert);
result.push_back(entry);
}
return result;
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index a6954a8..7a575a9 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -21,6 +21,7 @@
#include "ca-module.hpp"
#include "challenge-module.hpp"
#include "logging.hpp"
+#include "crypto-support/enc-tlv.hpp"
#include <ndn-cxx/util/io.hpp>
#include <ndn-cxx/security/verification-helpers.hpp>
#include <ndn-cxx/security/signing-helpers.hpp>
@@ -29,6 +30,8 @@
namespace ndn {
namespace ndncert {
+static const int IS_SUBNAME_MIN_OFFSET = 5;
+
_LOG_INIT(ndncert.ca);
CaModule::CaModule(Face& face, security::v2::KeyChain& keyChain,
@@ -45,525 +48,336 @@
CaModule::~CaModule()
{
- for (auto prefixId : m_interestFilterIds) {
- m_face.unsetInterestFilter(prefixId);
+ for (auto handle : m_interestFilterHandles) {
+ handle.cancel();
}
- for (auto prefixId : m_registeredPrefixIds) {
- m_face.unregisterPrefix(prefixId, nullptr, nullptr);
+ for (auto handle : m_registeredPrefixHandles) {
+ handle.unregister();
}
}
void
CaModule::registerPrefix()
{
- // register localhost list prefix
- Name localProbePrefix("/localhost/CA/_LIST");
- auto prefixId = m_face.setInterestFilter(InterestFilter(localProbePrefix),
- bind(&CaModule::handleLocalhostList, this, _2),
+ // register localhop discovery prefix
+ Name localhopProbePrefix("/localhop/CA/PROBE/INFO");
+ auto prefixId = m_face.setInterestFilter(InterestFilter(localhopProbePrefix),
+ bind(&CaModule::onProbe, this, _2),
bind(&CaModule::onRegisterFailed, this, _2));
- m_registeredPrefixIds.push_back(prefixId);
- _LOG_TRACE("Prefix " << localProbePrefix << " got registered");
+ m_registeredPrefixHandles.push_back(prefixId);
+ _LOG_TRACE("Prefix " << localhopProbePrefix << " got registered");
- // register prefixes for each CA
- for (const auto& item : m_config.m_caItems) {
- Name prefix = item.m_caName;
- prefix.append("CA");
+ // register prefixes
+ Name prefix = m_config.m_caName;
+ prefix.append("CA");
- prefixId = m_face.registerPrefix(prefix,
- [&] (const Name& name) {
- // NEW
- auto filterId = m_face.setInterestFilter(Name(name).append("_NEW"),
- bind(&CaModule::handleNew, this, _2, item));
- m_interestFilterIds.push_back(filterId);
- // SELECT
- filterId = m_face.setInterestFilter(Name(name).append("_SELECT"),
- bind(&CaModule::handleSelect, this, _2, item));
- m_interestFilterIds.push_back(filterId);
- // VALIDATE
- filterId = m_face.setInterestFilter(Name(name).append("_VALIDATE"),
- bind(&CaModule::handleValidate, this, _2, item));
- m_interestFilterIds.push_back(filterId);
- // STATUS
- filterId = m_face.setInterestFilter(Name(name).append("_STATUS"),
- bind(&CaModule::handleStatus, this, _2, item));
- m_interestFilterIds.push_back(filterId);
- // DOWNLOAD
- filterId = m_face.setInterestFilter(Name(name).append("_DOWNLOAD"),
- bind(&CaModule::handleDownload, this, _2, item));
- m_interestFilterIds.push_back(filterId);
- // PROBE
- if (item.m_probe != "") {
- filterId = m_face.setInterestFilter(Name(name).append("_PROBE"),
- bind(&CaModule::handleProbe, this, _2, item));
- m_interestFilterIds.push_back(filterId);
- }
- // LIST
- if (item.m_relatedCaList.size() > 0) {
- filterId = m_face.setInterestFilter(Name(name).append("_LIST"),
- bind(&CaModule::handleList, this, _2, item));
- m_interestFilterIds.push_back(filterId);
- }
- _LOG_TRACE("Prefix " << name << " got registered");
- },
- bind(&CaModule::onRegisterFailed, this, _2));
- m_registeredPrefixIds.push_back(prefixId);
- }
+ prefixId = m_face.registerPrefix(prefix,
+ [&] (const Name& name) {
+ // register PROBE prefix
+ auto filterId = m_face.setInterestFilter(Name(name).append("_PROBE"),
+ bind(&CaModule::onProbe, this, _2));
+ m_interestFilterHandles.push_back(filterId);
+
+ // register NEW prefix
+ filterId = m_face.setInterestFilter(Name(name).append("_NEW"),
+ bind(&CaModule::onNew, this, _2));
+ m_interestFilterHandles.push_back(filterId);
+
+ // register SELECT prefix
+ filterId = m_face.setInterestFilter(Name(name).append("_CHALLENGE"),
+ bind(&CaModule::onChallenge, this, _2));
+ m_interestFilterHandles.push_back(filterId);
+
+ // register DOWNLOAD prefix
+ filterId = m_face.setInterestFilter(Name(name).append("_DOWNLOAD"),
+ bind(&CaModule::onDownload, this, _2));
+ m_interestFilterHandles.push_back(filterId);
+ _LOG_TRACE("Prefix " << name << " got registered");
+ },
+ bind(&CaModule::onRegisterFailed, this, _2));
+ m_registeredPrefixHandles.push_back(prefixId);
}
bool
-CaModule::setProbeHandler(const Name caName, const ProbeHandler& handler)
+CaModule::setProbeHandler(const ProbeHandler& handler)
{
- for (auto& entry : m_config.m_caItems) {
- if (entry.m_caName == caName) {
- entry.m_probeHandler = handler;
- return true;
- }
- }
+ m_config.m_probeHandler = handler;
return false;
}
bool
-CaModule::setRecommendCaHandler(const Name caName, const RecommendCaHandler& handler)
+CaModule::setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback)
{
- for (auto& entry : m_config.m_caItems) {
- if (entry.m_caName == caName) {
- entry.m_recommendCaHandler = handler;
- return true;
- }
- }
- return false;
-}
-
-bool
-CaModule::setStatusUpdateCallback(const Name caName, const StatusUpdateCallback& onUpateCallback)
-{
- for (auto& entry : m_config.m_caItems) {
- if (entry.m_caName == caName) {
- entry.m_statusUpdateCallback = onUpateCallback;
- return true;
- }
- }
+ m_config.m_statusUpdateCallback = onUpdateCallback;
return false;
}
void
-CaModule::handleLocalhostList(const Interest& request)
+CaModule::onProbe(const Interest& request)
{
- _LOG_TRACE("Got Localhost LIST request");
+ // PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent|INFO]
+ _LOG_TRACE("Receive PROBE request");
+ JsonSection contentJson;
- JsonSection root;
- JsonSection caListSection;
-
- for (const auto& entry : m_config.m_caItems) {
- JsonSection caItem;
-
- const auto& pib = m_keyChain.getPib();
- auto identity = pib.getIdentity(entry.m_caName);
- auto cert = identity.getDefaultKey().getDefaultCertificate();
-
- // ca-prefix
- Name caName = entry.m_caName;
- caName.append("CA");
- caItem.put("ca-prefix", caName.toUri());
-
- // ca-info
- std::string caInfo;
- if (entry.m_caInfo == "") {
- caInfo = "Issued by " + cert.getSignature().getKeyLocator().getName().toUri();
+ // process PROBE INFO requests
+ if (readString(request.getName().at(-1)) == "INFO") {
+ contentJson = genProbeResponseJson();
+ }
+ else {
+ // if not a PROBE INFO, find an available name
+ std::string availableId = "";
+ const auto& parameterJson = jsonFromBlock(request.getApplicationParameters());
+ std::string probeInfoStr = parameterJson.get(JSON_CLIENT_PROBE_INFO, "");
+ if (m_config.m_probeHandler) {
+ try {
+ availableId = m_config.m_probeHandler(probeInfoStr);
+ }
+ catch (const std::exception& e) {
+ _LOG_TRACE("Cannot find PROBE input from PROBE parameters " << e.what());
+ return;
+ }
}
else {
- caInfo = entry.m_caInfo;
+ // if there is no app-specified name lookup, use a random name id
+ availableId = std::to_string(random::generateSecureWord64());
}
- caItem.put("ca-info", caInfo);
-
- // probe is always false for local client
-
- // ca-target list
- caItem.put("target-list", entry.m_targetedList);
-
- // certificate
- std::stringstream ss;
- io::save(cert, ss);
- caItem.put("certificate", ss.str());
-
- caListSection.push_back(std::make_pair("", caItem));
+ Name newIdentityName = m_config.m_caName;
+ _LOG_TRACE("Handle PROBE: generate an identity " << newIdentityName);
+ newIdentityName.append(availableId);
+ contentJson = genProbeResponseJson(newIdentityName.toUri());
}
- root.add_child("ca-list", caListSection);
-
- Data result;
- Name dataName = request.getName();
- dataName.appendTimestamp();
- result.setName(dataName);
- result.setContent(dataContentFromJson(root));
- m_keyChain.sign(result, signingByIdentity(m_keyChain.getPib().getDefaultIdentity().getName()));
- m_face.put(result);
-}
-
-void
-CaModule::handleList(const Interest& request, const CaItem& caItem)
-{
- _LOG_TRACE("Got LIST request");
-
- bool getRecommendation = false;
- Name recommendedCaName;
- std::string identityName;
-
- // LIST naming convention: /CA-prefix/CA/_LIST/[optional info]
- if (readString(request.getName().at(-1)) != "_LIST" && caItem.m_recommendCaHandler) {
- const auto& additionInfo = readString(request.getName().at(-1));
- try {
- std::tie(recommendedCaName, identityName) = caItem.m_recommendCaHandler(additionInfo, caItem.m_relatedCaList);
- getRecommendation = true;
- }
- catch (const std::exception& e) {
- _LOG_TRACE("Cannot recommend CA for LIST request. Degrade to non-target list." << e.what());
- }
- }
-
- JsonSection root;
- JsonSection caListSection;
- if (getRecommendation) {
- // JSON format
- // {
- // "recommended-ca": "/ndn/edu/ucla"
- // "recommended-identity": "something"
- // "trust-schema": "schema Data packet name"
- // }
- root.put("recommended-ca", recommendedCaName.toUri());
- root.put("recommended-identity", identityName);
- }
- else {
- // JSON format
- // {
- // "ca-list": [
- // {"ca-prefix": "/ndn/edu/ucla"},
- // {"ca-prefix": "/ndn/edu/memphis"},
- // ...
- // ]
- // "trust-schema": "schema Data packet name"
- // }
- for (const auto& entry : caItem.m_relatedCaList) {
- JsonSection caItem;
- caItem.put("ca-prefix", entry.toUri());
- caListSection.push_back(std::make_pair("", caItem));
- }
- root.add_child("ca-list", caListSection);
- }
-
- // TODO: add trust schema
- std::string schemaDataName = "TODO: add trust schema";
- root.put("trust-schema", schemaDataName);
-
- Data result;
- Name dataName = request.getName();
- dataName.appendTimestamp();
- result.setName(dataName);
- result.setContent(dataContentFromJson(root));
- m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
- m_face.put(result);
-}
-
-void
-CaModule::handleProbe(const Interest& request, const CaItem& caItem)
-{
- // PROBE Naming Convention: /CA-prefix/CA/_PROBE/<Probe Information>
- _LOG_TRACE("Handle PROBE request");
-
- std::string identifier;
- if (caItem.m_probeHandler) {
- try {
- identifier = caItem.m_probeHandler(readString(request.getName().at(caItem.m_caName.size() + 2)));
- }
- catch (const std::exception& e) {
- _LOG_TRACE("Cannot generate identifier for PROBE request " << e.what());
- return;
- }
- }
- else {
- identifier = readString(request.getName().at(caItem.m_caName.size() + 2));
- }
- Name identityName = caItem.m_caName;
- identityName.append(identifier);
Data result;
result.setName(request.getName());
- result.setContent(dataContentFromJson(genResponseProbeJson(identityName, "")));
- m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
+ result.setContent(dataContentFromJson(contentJson));
+ m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
m_face.put(result);
-
- _LOG_TRACE("Handle PROBE: generate identity " << identityName);
+ _LOG_TRACE("Handle PROBE: send out the PROBE response");
}
void
-CaModule::handleNew(const Interest& request, const CaItem& caItem)
+CaModule::onNew(const Interest& request)
{
- // NEW Naming Convention: /CA-prefix/CA/_NEW/<certificate-request>/[signature]
- _LOG_TRACE("Handle NEW request");
+ // NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
- security::v2::Certificate clientCert;
+ // get ECDH pub key and cert request
+ const auto& parameterJson = jsonFromBlock(request.getApplicationParameters());
+ std::string peerKeyBase64 = parameterJson.get(JSON_CLIENT_ECDH, "");
+
+ // get server's ECDH pub key
+ auto myEcdhPubKeyBase64 = m_ecdh.getBase64PubKey();
+ m_ecdh.deriveSecret(peerKeyBase64);
+ // generate salt for HKDF
+ auto saltInt = random::generateSecureWord64();
+ uint8_t salt[sizeof(saltInt)];
+ std::memcpy(salt, &saltInt, sizeof(saltInt));
+ // hkdf
+ hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
+ salt, sizeof(saltInt), m_aesKey, 32);
+
+ // parse certificate request
+ std::string certRequestStr = parameterJson.get(JSON_CLIENT_CERT_REQ, "");
+ shared_ptr<security::v2::Certificate> clientCert = nullptr;
try {
- clientCert.wireDecode(request.getName().at(caItem.m_caName.size() + 2).blockFromValue());
+ std::stringstream ss(certRequestStr);
+ clientCert = io::load<security::v2::Certificate>(ss);
}
catch (const std::exception& e) {
_LOG_ERROR("Unrecognized certificate request " << e.what());
return;
}
- if (!security::verifySignature(clientCert, clientCert)) {
+ // verify the self-signed certificate and the request
+ if (!m_config.m_caName.isPrefixOf(clientCert->getName()) // under ca prefix
+ || !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
+ || clientCert->getName().size() != m_config.m_caName.size() + IS_SUBNAME_MIN_OFFSET) {
+ _LOG_ERROR("Invalid self-signed certificate name " << clientCert->getName());
+ return;
+ }
+ if (!security::verifySignature(*clientCert, *clientCert)) {
_LOG_TRACE("Cert request with bad signature.");
return;
}
- if (!security::verifySignature(request, clientCert)) {
+ if (!security::verifySignature(request, *clientCert)) {
_LOG_TRACE("Interest with bad signature.");
return;
}
+ // create new request instance
std::string requestId = std::to_string(random::generateWord64());
- CertificateRequest certRequest(caItem.m_caName, requestId, clientCert);
- certRequest.setStatus(ChallengeModule::WAIT_SELECTION);
+ CertificateRequest certRequest(m_config.m_caName, requestId, STATUS_BEFORE_CHALLENGE, *clientCert);
try {
m_storage->addRequest(certRequest);
}
catch (const std::exception& e) {
- _LOG_TRACE("Cannot add new request instance " << e.what());
+ _LOG_TRACE("Cannot add new request instance into the storage" << e.what());
return;
}
Data result;
result.setName(request.getName());
- result.setContent(dataContentFromJson(genResponseNewJson(requestId, certRequest.getStatus(),
- caItem.m_supportedChallenges)));
- m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
+ result.setContent(dataContentFromJson(genNewResponseJson(myEcdhPubKeyBase64,
+ std::to_string(saltInt),
+ certRequest,
+ m_config.m_supportedChallenges)));
+ m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
m_face.put(result);
- if (caItem.m_statusUpdateCallback) {
- caItem.m_statusUpdateCallback(certRequest);
+ if (m_config.m_statusUpdateCallback) {
+ m_config.m_statusUpdateCallback(certRequest);
}
}
void
-CaModule::handleSelect(const Interest& request, const CaItem& caItem)
+CaModule::onChallenge(const Interest& request)
{
- // SELECT Naming Convention: /CA-prefix/CA/_SELECT/{Request-ID JSON}/<ChallengeID>/
- // {Param JSON}/[Signature components]
- _LOG_TRACE("Handle SELECT request");
-
- CertificateRequest certRequest = getCertificateRequest(request, caItem.m_caName);
- if (certRequest.getRequestId().empty()) {
+ // get certificate request state
+ CertificateRequest certRequest = getCertificateRequest(request);
+ if (certRequest.m_requestId == "") {
+ // cannot get the request state
return;
}
-
- if (!security::verifySignature(request, certRequest.getCert())) {
+ // verify signature
+ if (!security::verifySignature(request, certRequest.m_cert)) {
_LOG_TRACE("Interest with bad signature.");
return;
}
+ // decrypt the parameters
+ auto paramJsonPayload = parseEncBlock(m_ecdh.context->sharedSecret,
+ m_ecdh.context->sharedSecretLen,
+ request.getApplicationParameters());
+ std::string paramJsonStr((const char*)paramJsonPayload.data(), paramJsonPayload.size());
+ std::istringstream ss(paramJsonStr);
+ JsonSection paramJson;
+ boost::property_tree::json_parser::read_json(ss, paramJson);
- std::string challengeType;
- try {
- challengeType = readString(request.getName().at(caItem.m_caName.size() + 3));
- }
- catch (const std::exception& e) {
- _LOG_ERROR(e.what());
- return;
- }
- _LOG_TRACE("SELECT request choosing challenge " << challengeType);
+ // load the corresponding challenge module
+ std::string challengeType = paramJson.get<std::string>(JSON_CLIENT_SELECTED_CHALLENGE);
auto challenge = ChallengeModule::createChallengeModule(challengeType);
+ JsonSection contentJson;
if (challenge == nullptr) {
_LOG_TRACE("Unrecognized challenge type " << challengeType);
- return;
- }
- JsonSection contentJson = challenge->handleChallengeRequest(request, certRequest);
- if (certRequest.getStatus() == ChallengeModule::FAILURE) {
- m_storage->deleteRequest(certRequest.getRequestId());
+ certRequest.m_status = STATUS_FAILURE;
+ certRequest.m_challengeStatus = CHALLENGE_STATUS_UNKNOWN_CHALLENGE;
+ contentJson = genChallengeResponseJson(certRequest);
}
else {
- try {
- m_storage->updateRequest(certRequest);
+ _LOG_TRACE("CHALLENGE module to be load: " << challengeType);
+ // let challenge module handle the request
+ challenge->handleChallengeRequest(paramJson, certRequest);
+ if (certRequest.m_status == STATUS_FAILURE) {
+ // if challenge failed
+ m_storage->deleteRequest(certRequest.m_requestId);
+ contentJson = genChallengeResponseJson(certRequest);
+ _LOG_TRACE("Challenge failed");
}
- catch (const std::exception& e) {
- _LOG_TRACE("Cannot update request instance " << e.what());
- return;
- }
- }
-
- Data result;
- result.setName(request.getName());
- result.setContent(dataContentFromJson(contentJson));
- m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
- m_face.put(result);
-
- if (caItem.m_statusUpdateCallback) {
- caItem.m_statusUpdateCallback(certRequest);
- }
-}
-
-void
-CaModule::handleValidate(const Interest& request, const CaItem& caItem)
-{
- // VALIDATE Naming Convention: /CA-prefix/CA/_VALIDATE/{Request-ID JSON}/<ChallengeID>/
- // {Param JSON}/[Signature components]
- _LOG_TRACE("Handle VALIDATE request");
-
- CertificateRequest certRequest = getCertificateRequest(request, caItem.m_caName);
- if (certRequest.getRequestId().empty()) {
- return;
- }
-
- if (!security::verifySignature(request, certRequest.getCert())) {
- _LOG_TRACE("Interest with bad signature.");
- return;
- }
-
- std::string challengeType = certRequest.getChallengeType();
- auto challenge = ChallengeModule::createChallengeModule(challengeType);
- if (challenge == nullptr) {
- _LOG_TRACE("Unrecognized challenge type " << challengeType);
- return;
- }
- JsonSection contentJson = challenge->handleChallengeRequest(request, certRequest);
- if (certRequest.getStatus() == ChallengeModule::FAILURE) {
- m_storage->deleteRequest(certRequest.getRequestId());
- }
- else {
- try {
- m_storage->updateRequest(certRequest);
- }
- catch (const std::exception& e) {
- _LOG_TRACE("Cannot update request instance " << e.what());
- return;
- }
- }
- Data result;
- result.setName(request.getName());
- result.setContent(dataContentFromJson(contentJson));
- m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
- m_face.put(result);
-
- if (certRequest.getStatus() == ChallengeModule::SUCCESS) {
- auto issuedCert = issueCertificate(certRequest, caItem);
- if (caItem.m_statusUpdateCallback) {
- certRequest.setCert(issuedCert);
- caItem.m_statusUpdateCallback(certRequest);
- }
- try {
- m_storage->addCertificate(certRequest.getRequestId(), issuedCert);
- m_storage->deleteRequest(certRequest.getRequestId());
- _LOG_TRACE("New Certificate Issued " << issuedCert.getName());
- }
- catch (const std::exception& e) {
- _LOG_ERROR("Cannot add issued cert and remove the request " << e.what());
- return;
- }
- }
-}
-
-void
-CaModule::handleStatus(const Interest& request, const CaItem& caItem)
-{
- // STATUS Naming Convention: /CA-prefix/CA/_STATUS/{Request-ID JSON}/[Signature components]
- _LOG_TRACE("Handle STATUS request");
-
- CertificateRequest certRequest = getCertificateRequest(request, caItem.m_caName);
- if (certRequest.getRequestId().empty()) {
- return;
- }
-
- if (!security::verifySignature(request, certRequest.getCert())) {
- _LOG_TRACE("Interest with bad signature.");
- return;
- }
-
- std::string challengeType = certRequest.getChallengeType();
- auto challenge = ChallengeModule::createChallengeModule(challengeType);
- if (challenge == nullptr) {
- _LOG_TRACE("Unrecognized challenge type " << challengeType);
- return;
- }
- JsonSection contentJson = challenge->handleChallengeRequest(request, certRequest);
-
- Data result;
- result.setName(request.getName());
- result.setContent(dataContentFromJson(contentJson));
- m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
- m_face.put(result);
-}
-
-void
-CaModule::handleDownload(const Interest& request, const CaItem& caItem)
-{
- // DOWNLOAD Naming Convention: /CA-prefix/CA/_DOWNLOAD/{Request-ID JSON}
- _LOG_TRACE("Handle DOWNLOAD request");
-
- Data result;
- result.setName(request.getName());
- if (readString(request.getName().at(-1)) == "ANCHOR") {
- JsonSection contentJson;
-
- const auto& pib = m_keyChain.getPib();
- auto identity = pib.getIdentity(caItem.m_caName);
- auto cert = identity.getDefaultKey().getDefaultCertificate();
-
- // ca-prefix
- Name caName = caItem.m_caName;
- caName.append("CA");
- contentJson.put("ca-prefix", caName.toUri());
-
- // ca-info
- std::string caInfo;
- if (caItem.m_caInfo == "") {
- caInfo = "Issued by " + cert.getSignature().getKeyLocator().getName().toUri();
+ else if (certRequest.m_status == STATUS_PENDING) {
+ // if challenge succeeded
+ auto issuedCert = issueCertificate(certRequest);
+ certRequest.m_cert = issuedCert;
+ certRequest.m_status = STATUS_SUCCESS;
+ try {
+ m_storage->addCertificate(certRequest.m_requestId, issuedCert);
+ m_storage->deleteRequest(certRequest.m_requestId);
+ _LOG_TRACE("New Certificate Issued " << issuedCert.getName());
+ }
+ catch (const std::exception& e) {
+ _LOG_ERROR("Cannot add issued cert and remove the request " << e.what());
+ return;
+ }
+ if (m_config.m_statusUpdateCallback) {
+ m_config.m_statusUpdateCallback(certRequest);
+ }
+ contentJson = genChallengeResponseJson(certRequest);
+ contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
+ _LOG_TRACE("Challenge succeeded. Certificate has been issued");
}
else {
- caInfo = caItem.m_caInfo;
+ try {
+ m_storage->updateRequest(certRequest);
+ }
+ catch (const std::exception& e) {
+ _LOG_TRACE("Cannot update request instance " << e.what());
+ return;
+ }
+ contentJson = genChallengeResponseJson(certRequest);
+ _LOG_TRACE("No failure no success. Challenge moves on");
}
- contentJson.put("ca-info", caInfo);
-
- // probe
- contentJson.put("probe", caItem.m_probe);
-
- // ca-target list
- contentJson.put("target-list", caItem.m_targetedList);
-
- // certificate
- std::stringstream ss;
- io::save(cert, ss);
- contentJson.put("certificate", ss.str());
-
- result.setContent(dataContentFromJson(contentJson));
}
- else {
- JsonSection requestIdJson = jsonFromNameComponent(request.getName(), caItem.m_caName.size() + 2);
- std::string requestId = requestIdJson.get(JSON_REQUEST_ID, "");
- security::v2::Certificate signedCert;
- try {
- signedCert = m_storage->getCertificate(requestId);
- }
- catch (const std::exception& e) {
- _LOG_ERROR(e.what());
- return;
- }
- result.setContent(signedCert.wireEncode());
+
+ Data result;
+ result.setName(request.getName());
+
+ // encrypt the content
+ std::stringstream ss2;
+ boost::property_tree::write_json(ss2, contentJson);
+ auto payload = ss2.str();
+ auto contentBlock = genEncBlock(tlv::Content, m_ecdh.context->sharedSecret,
+ m_ecdh.context->sharedSecretLen,
+ (const uint8_t*)payload.c_str(), payload.size());
+ result.setContent(contentBlock);
+ m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
+ m_face.put(result);
+
+ if (m_config.m_statusUpdateCallback) {
+ m_config.m_statusUpdateCallback(certRequest);
}
- m_keyChain.sign(result, signingByIdentity(caItem.m_caName));
+}
+
+void
+CaModule::onDownload(const Interest& request)
+{
+ auto requestId = readString(request.getName().at(-1));
+ security::v2::Certificate signedCert;
+ try {
+ signedCert = m_storage->getCertificate(requestId);
+ }
+ catch (const std::exception& e) {
+ _LOG_ERROR("Cannot read signed cert " << requestId << " from ca database " << e.what());
+ return;
+ }
+ Data result;
+ result.setName(request.getName());
+ result.setContent(signedCert.wireEncode());
+ m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
m_face.put(result);
}
security::v2::Certificate
-CaModule::issueCertificate(const CertificateRequest& certRequest, const CaItem& caItem)
+CaModule::issueCertificate(const CertificateRequest& certRequest)
{
- Name certName = certRequest.getCert().getKeyName();
- certName.append("NDNCERT").appendVersion();
+ auto expectedPeriod =
+ certRequest.m_cert.getValidityPeriod().getPeriod();
+
+ time::system_clock::TimePoint startingTime, endingTime;
+ if (expectedPeriod.first > time::system_clock::now()
+ && expectedPeriod.first < time::system_clock::now()
+ + m_config.m_validityPeriod)
+ {
+ startingTime = expectedPeriod.first;
+ }
+ else {
+ startingTime = time::system_clock::now();
+ }
+ if (expectedPeriod.second < time::system_clock::now() + m_config.m_validityPeriod) {
+ endingTime = expectedPeriod.second;
+ }
+ else {
+ endingTime = time::system_clock::now() + m_config.m_validityPeriod;
+ }
+ security::ValidityPeriod period(startingTime, endingTime);
security::v2::Certificate newCert;
+
+ Name certName = certRequest.m_cert.getKeyName();
+ certName.append("NDNCERT").append(std::to_string(random::generateSecureWord64()));
newCert.setName(certName);
- newCert.setContent(certRequest.getCert().getContent());
- _LOG_TRACE("cert request content " << certRequest.getCert());
+ newCert.setContent(certRequest.m_cert.getContent());
+ _LOG_TRACE("cert request content " << certRequest.m_cert);
SignatureInfo signatureInfo;
- security::ValidityPeriod period(time::system_clock::now(),
- time::system_clock::now() + caItem.m_validityPeriod);
signatureInfo.setValidityPeriod(period);
security::SigningInfo signingInfo(security::SigningInfo::SIGNER_TYPE_ID,
- caItem.m_caName, signatureInfo);
- newCert.setFreshnessPeriod(caItem.m_freshnessPeriod);
+ m_config.m_caName, signatureInfo);
+ newCert.setFreshnessPeriod(m_config.m_freshnessPeriod);
m_keyChain.sign(newCert, signingInfo);
_LOG_TRACE("new cert got signed" << newCert);
@@ -571,10 +385,10 @@
}
CertificateRequest
-CaModule::getCertificateRequest(const Interest& request, const Name& caName)
+CaModule::getCertificateRequest(const Interest& request)
{
- JsonSection requestIdJson = jsonFromNameComponent(request.getName(), caName.size() + 2);
- std::string requestId = requestIdJson.get(JSON_REQUEST_ID, "");
+ std::string requestId = readString(request.getName().at(m_config.m_caName.size() + 2));
+ _LOG_TRACE("Requet Id to query the database " << requestId);
CertificateRequest certRequest;
try {
certRequest = m_storage->getRequest(requestId);
@@ -585,6 +399,108 @@
return certRequest;
}
+/**
+ * @brief Generate JSON file to response PROBE insterest
+ *
+ * PROBE response JSON format:
+ * {
+ * "name": "@p identifier",
+ * "ca-config": "@p caInformation"
+ * }
+ */
+const JsonSection
+CaModule::genProbeResponseJson(const Name& identifier)
+{
+ JsonSection root;
+ root.put(JSON_CA_NAME, identifier.toUri());
+ return root;
+}
+
+/**
+ * @brief Generate JSON file to response NEW interest
+ *
+ * Target JSON format:
+ * {
+ * "ecdh-pub": "@p echdPub",
+ * "salt": "@p salt"
+ * "request-id": "@p requestId",
+ * "status": "@p status",
+ * "challenges": [
+ * {
+ * "challenge-id": ""
+ * },
+ * {
+ * "challenge-id": ""
+ * },
+ * ...
+ * ]
+ * }
+ */
+const JsonSection
+CaModule::genProbeResponseJson()
+{
+ JsonSection root;
+ // ca-prefix
+ Name caName = m_config.m_caName;
+ root.put("ca-prefix", caName.toUri());
+
+ // ca-info
+ const auto& pib = m_keyChain.getPib();
+ auto identity = pib.getIdentity(m_config.m_caName);
+ auto cert = identity.getDefaultKey().getDefaultCertificate();
+ std::string caInfo = "";
+ if (m_config.m_caInfo == "") {
+ caInfo = "Issued by " + cert.getSignature().getKeyLocator().getName().toUri();
+ }
+ else {
+ caInfo = m_config.m_caInfo;
+ }
+ root.put("ca-info", caInfo);
+
+ // probe
+ root.put("probe", m_config.m_probe);
+
+ // certificate
+ std::stringstream ss;
+ io::save(cert, ss);
+ root.put("certificate", ss.str());
+
+ return root;
+}
+
+const JsonSection
+CaModule::genNewResponseJson(const std::string& ecdhKey, const std::string& salt,
+ const CertificateRequest& request,
+ const std::list<std::string>& challenges)
+{
+ JsonSection root;
+ JsonSection challengesSection;
+ root.put(JSON_CA_ECDH, ecdhKey);
+ root.put(JSON_CA_SALT, salt);
+ root.put(JSON_CA_EQUEST_ID, request.m_requestId);
+ root.put(JSON_CA_STATUS, std::to_string(request.m_status));
+
+ for (const auto& entry : challenges) {
+ JsonSection challenge;
+ challenge.put(JSON_CA_CHALLENGE_ID, entry);
+ challengesSection.push_back(std::make_pair("", challenge));
+ }
+ root.add_child(JSON_CA_CHALLENGES, challengesSection);
+ return root;
+}
+
+const JsonSection
+CaModule::genChallengeResponseJson(const CertificateRequest& request)
+{
+ JsonSection root;
+ JsonSection challengesSection;
+ root.put(JSON_CA_STATUS, request.m_status);
+ root.put(JSON_CHALLENGE_STATUS, request.m_challengeStatus);
+ root.put(JSON_CHALLENGE_REMAINING_TRIES, std::to_string(request.m_remainingTries));
+ root.put(JSON_CHALLENGE_REMAINING_TIME, std::to_string(request.m_remainingTime));
+ return root;
+}
+
void
CaModule::onRegisterFailed(const std::string& reason)
{
@@ -600,14 +516,14 @@
}
JsonSection
-CaModule::jsonFromNameComponent(const Name& name, int pos)
+CaModule::jsonFromBlock(const Block& block)
{
std::string jsonString;
try {
- jsonString = encoding::readString(name.at(pos));
+ jsonString = encoding::readString(block);
}
catch (const std::exception& e) {
- _LOG_ERROR(e.what());
+ _LOG_ERROR("Cannot read JSON string from TLV Value" << e.what());
return JsonSection();
}
std::istringstream ss(jsonString);
diff --git a/src/ca-module.hpp b/src/ca-module.hpp
index 23386a2..47e30c9 100644
--- a/src/ca-module.hpp
+++ b/src/ca-module.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -22,8 +22,8 @@
#define NDNCERT_CA_MODULE_HPP
#include "ca-config.hpp"
+#include "crypto-support/crypto-helper.hpp"
#include "ca-storage.hpp"
-#include "json-helper.hpp"
namespace ndn {
namespace ndncert {
@@ -59,50 +59,32 @@
}
bool
- setProbeHandler(const Name caName, const ProbeHandler& handler);
+ setProbeHandler(const ProbeHandler& handler);
bool
- setRecommendCaHandler(const Name caName, const RecommendCaHandler& handler);
-
- bool
- setStatusUpdateCallback(const Name caName, const StatusUpdateCallback& onUpateCallback);
+ setStatusUpdateCallback(const StatusUpdateCallback& onUpdateCallback);
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
- handleLocalhostList(const Interest& query);
+ onProbe(const Interest& request);
void
- handleList(const Interest& request, const CaItem& caItem);
+ onNew(const Interest& request);
void
- handleProbe(const Interest& request, const CaItem& caItem);
+ onChallenge(const Interest& request);
void
- handleNew(const Interest& request, const CaItem& caItem);
-
- void
- handleSelect(const Interest& request, const CaItem& caItem);
-
- void
- handleValidate(const Interest& request, const CaItem& caItem);
-
- void
- handleStatus(const Interest& request, const CaItem& caItem);
-
- void
- handleDownload(const Interest& request, const CaItem& caItem);
+ onDownload(const Interest& request);
void
onRegisterFailed(const std::string& reason);
CertificateRequest
- getCertificateRequest(const Interest& request, const Name& caName);
+ getCertificateRequest(const Interest& request);
security::v2::Certificate
- issueCertificate(const CertificateRequest& certRequest, const CaItem& caItem);
-
- static JsonSection
- jsonFromNameComponent(const Name& name, int pos);
+ issueCertificate(const CertificateRequest& certRequest);
static Block
dataContentFromJson(const JsonSection& jsonSection);
@@ -110,14 +92,34 @@
void
registerPrefix();
+ static JsonSection
+ jsonFromBlock(const Block& block);
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ const JsonSection
+ genProbeResponseJson(const Name& identifier);
+
+ const JsonSection
+ genProbeResponseJson();
+
+ const JsonSection
+ genNewResponseJson(const std::string& ecdhKey, const std::string& salt,
+ const CertificateRequest& request, const std::list<std::string>& challenges);
+
+ const JsonSection
+ genChallengeResponseJson(const CertificateRequest& request);
+
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
Face& m_face;
CaConfig m_config;
unique_ptr<CaStorage> m_storage;
security::v2::KeyChain& m_keyChain;
- std::list<const RegisteredPrefixId*> m_registeredPrefixIds;
- std::list<const InterestFilterId*> m_interestFilterIds;
+ std::list<RegisteredPrefixHandle> m_registeredPrefixHandles;
+ std::list<InterestFilterHandle> m_interestFilterHandles;
+
+ ECDHState m_ecdh;
+ uint8_t m_aesKey[32] = {0};
};
} // namespace ndncert
diff --git a/src/ca-storage.cpp b/src/ca-storage.cpp
index ebe5c98..fbdae64 100644
--- a/src/ca-storage.cpp
+++ b/src/ca-storage.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
diff --git a/src/ca-storage.hpp b/src/ca-storage.hpp
index ab5e38d..2cf7b7e 100644
--- a/src/ca-storage.hpp
+++ b/src/ca-storage.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
diff --git a/src/certificate-request.cpp b/src/certificate-request.cpp
index ac1a216..8db1f6f 100644
--- a/src/certificate-request.cpp
+++ b/src/certificate-request.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -26,49 +26,54 @@
CertificateRequest::CertificateRequest() = default;
-CertificateRequest::CertificateRequest(const Name& caName,
- const std::string& requestId,
- const security::v2::Certificate& cert)
- : m_caName(caName)
- , m_requestId(requestId)
- , m_cert(static_cast<const Data&>(cert))
-{
-}
-
-CertificateRequest::CertificateRequest(const Name& caName,
- const std::string& requestId,
- const std::string& status,
- const std::string& challengeType,
- const std::string& challengeSecrets,
+CertificateRequest::CertificateRequest(const Name& caName, const std::string& requestId, int status,
const security::v2::Certificate& cert)
: m_caName(caName)
, m_requestId(requestId)
, m_status(status)
- , m_challengeType(challengeType)
- , m_cert(static_cast<const Data&>(cert))
+ , m_cert(cert)
{
- std::istringstream ss(challengeSecrets);
- boost::property_tree::json_parser::read_json(ss, m_challengeSecrets);
+}
+
+CertificateRequest::CertificateRequest(const Name& caName, const std::string& requestId, int status,
+ const std::string& challengeStatus, const std::string& challengeType,
+ const std::string& challengeTp, int remainingTime, int remainingTries,
+ const JsonSection& challengeSecrets, const security::v2::Certificate& cert)
+ : m_caName(caName)
+ , m_requestId(requestId)
+ , m_status(status)
+ , m_cert(cert)
+ , m_challengeStatus(challengeStatus)
+ , m_challengeType(challengeType)
+ , m_challengeTp(challengeTp)
+ , m_remainingTime(remainingTime)
+ , m_remainingTries(remainingTries)
+ , m_challengeSecrets(challengeSecrets)
+{
}
std::ostream&
operator<<(std::ostream& os, const CertificateRequest& request)
{
os << "Request CA name:\n";
- os << " " << request.getCaName() << "\n";
+ os << " " << request.m_caName << "\n";
os << "Request ID:\n";
- os << " " << request.getRequestId() << "\n";
- if (request.getStatus() != "") {
+ os << " " << request.m_requestId << "\n";
+ if (request.m_status != -1) {
os << "Request Status:\n";
- os << " " << request.getStatus() << "\n";
+ os << " " << request.m_status << "\n";
}
- if (request.getChallengeType() != "") {
+ if (request.m_challengeStatus != "") {
+ os << "Challenge Status:\n";
+ os << " " << request.m_challengeStatus << "\n";
+ }
+ if (request.m_challengeType != "") {
os << "Request Challenge Type:\n";
- os << " " << request.getChallengeType() << "\n";
+ os << " " << request.m_challengeType << "\n";
}
os << "Certificate:\n";
util::IndentedStream os2(os, " ");
- os2 << request.getCert();
+ os2 << request.m_cert;
return os;
}
diff --git a/src/certificate-request.hpp b/src/certificate-request.hpp
index d14b74d..8fa5a0d 100644
--- a/src/certificate-request.hpp
+++ b/src/certificate-request.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -40,95 +40,23 @@
{
public:
CertificateRequest();
-
- CertificateRequest(const Name& caName, const std::string& requestId,
- const security::v2::Certificate& cert);
-
- CertificateRequest(const Name& caName, const std::string& requestId,
- const std::string& status, const std::string& challengeType,
- const std::string& challengeSecrets,
- const security::v2::Certificate& cert);
-
- const Name&
- getCaName() const
- {
- return m_caName;
- }
-
- const std::string&
- getRequestId() const
- {
- return m_requestId;
- }
-
- const std::string&
- getStatus() const
- {
- return m_status;
- }
-
- const std::string&
- getChallengeType() const
- {
- return m_challengeType;
- }
-
- const JsonSection&
- getChallengeSecrets() const
- {
- return m_challengeSecrets;
- }
-
- const security::v2::Certificate&
- getCert() const
- {
- return m_cert;
- }
-
- void
- setCert(security::v2::Certificate cert)
- {
- m_cert = std::move(cert);
- }
-
- void
- setStatus(const std::string& status)
- {
- m_status = status;
- }
-
- void
- setChallengeType(const std::string& challengeType)
- {
- m_challengeType = challengeType;
- }
-
- void
- setChallengeSecrets(const JsonSection& challengeSecrets)
- {
- m_challengeSecrets = challengeSecrets;
- }
-
- bool
- isEmpty()
- {
- return m_requestId == "";
- }
-
-private:
+ CertificateRequest(const Name& caName, const std::string& requestId, int status, const security::v2::Certificate& cert);
+ CertificateRequest(const Name& caName, const std::string& requestId, int status,
+ const std::string& challengeStatus, const std::string& challengeType,
+ const std::string& challengeTp, int remainingTime, int remainingTries,
+ const JsonSection& challengeSecrets, const security::v2::Certificate& cert);
+public:
Name m_caName;
- std::string m_requestId;
- std::string m_status;
- std::string m_challengeType;
-
- /**
- * @brief Defined by ChallengeModule to store secret information.
- *
- * This field will be stored by CA.
- */
- JsonSection m_challengeSecrets;
-
+ std::string m_requestId = "";
+ int m_status = -1;
security::v2::Certificate m_cert;
+
+ std::string m_challengeStatus = "";
+ std::string m_challengeType = "";
+ std::string m_challengeTp = "";
+ int m_remainingTime = 0;
+ int m_remainingTries = 0;
+ JsonSection m_challengeSecrets;
};
std::ostream&
diff --git a/src/challenge-module.cpp b/src/challenge-module.cpp
index f40e5b9..8c332cb 100644
--- a/src/challenge-module.cpp
+++ b/src/challenge-module.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -19,19 +19,11 @@
*/
#include "challenge-module.hpp"
-#include "logging.hpp"
#include <ndn-cxx/util/random.hpp>
namespace ndn {
namespace ndncert {
-_LOG_INIT(ndncert.challenge-module);
-
-const std::string ChallengeModule::WAIT_SELECTION = "wait-selection";
-const std::string ChallengeModule::SUCCESS = "success";
-const std::string ChallengeModule::PENDING = "pending";
-const std::string ChallengeModule::FAILURE = "failure";
-
ChallengeModule::ChallengeModule(const std::string& uniqueType)
: CHALLENGE_TYPE(uniqueType)
{
@@ -47,89 +39,6 @@
return i == factory.end() ? nullptr : i->second();
}
-JsonSection
-ChallengeModule::handleChallengeRequest(const Interest& interest, CertificateRequest& request)
-{
- int pos = request.getCaName().size() + 1;
- const Name& interestName = interest.getName();
- std::string interestType = interestName.get(pos).toUri();
-
- _LOG_TRACE("Incoming challenge request. type: " << interestType);
-
- if (interestType == "_SELECT") {
- return processSelectInterest(interest, request);
- }
- else if (interestType == "_VALIDATE"){
- return processValidateInterest(interest, request);
- }
- else {
- return processStatusInterest(interest, request);
- }
-}
-
-std::list<std::string>
-ChallengeModule::getRequirementForSelect()
-{
- return getSelectRequirements();
-}
-
-std::list<std::string>
-ChallengeModule::getRequirementForValidate(const std::string& status)
-{
- return getValidateRequirements(status);
-}
-
-JsonSection
-ChallengeModule::genSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
-{
- return doGenSelectParamsJson(status, paramList);
-}
-
-JsonSection
-ChallengeModule::genValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
-{
- return doGenValidateParamsJson(status, paramList);
-}
-
-JsonSection
-ChallengeModule::processStatusInterest(const Interest& interest, const CertificateRequest& request)
-{
- // interest format: /CA/_STATUS/{"request-id":"id"}/<signature>
- if (request.getStatus() == SUCCESS) {
- Name downloadName = genDownloadName(request.getCaName(), request.getStatus());
- return genResponseChallengeJson(request.getRequestId(), request.getChallengeType(),
- SUCCESS, downloadName);
- }
- else
- return genResponseChallengeJson(request.getRequestId(), request.getChallengeType(),
- request.getStatus());
-}
-
-JsonSection
-ChallengeModule::getJsonFromNameComponent(const Name& name, int pos)
-{
- std::string jsonString = encoding::readString(name.get(pos));
- std::istringstream ss(jsonString);
- JsonSection json;
- boost::property_tree::json_parser::read_json(ss, json);
- return json;
-}
-
-Name
-ChallengeModule::genDownloadName(const Name& caName, const std::string& requestId)
-{
- JsonSection json;
- json.put(JSON_REQUEST_ID, requestId);
- std::stringstream ss;
- boost::property_tree::write_json(ss, json);
- Block jsonBlock = makeStringBlock(ndn::tlv::GenericNameComponent, ss.str());
- Name name = caName;
- name.append("_DOWNLOAD").append(jsonBlock);
- return name;
-}
-
ChallengeModule::ChallengeFactory&
ChallengeModule::getFactory()
{
@@ -153,5 +62,16 @@
return result;
}
+void
+ChallengeModule::updateRequestOnChallengeEnd(CertificateRequest& request)
+{
+ request.m_challengeSecrets = JsonSection();
+ request.m_challengeTp = "";
+ request.m_challengeType = "";
+ request.m_remainingTime = 0;
+ request.m_remainingTries = 0;
+}
+
+
} // namespace ndncert
} // namespace ndn
diff --git a/src/challenge-module.hpp b/src/challenge-module.hpp
index b2d39ad..ab15be8 100644
--- a/src/challenge-module.hpp
+++ b/src/challenge-module.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -23,7 +23,6 @@
#include "ndncert-common.hpp"
#include "certificate-request.hpp"
-#include "json-helper.hpp"
namespace ndn {
namespace ndncert {
@@ -63,121 +62,27 @@
createChallengeModule(const std::string& ChallengeType);
// For CA
- /**
- * @brief Handle the challenge related interest and update certificate request.
- * @note Should be used by CA Module
- * @note Signature of interest should already be validated by CA Module
- *
- * When CA receives a SELECT or a VALIDATE or a STATUS interest, CA should invoke the function
- * to enable selected challenge to go on the verification process.
- *
- * @param interest The request interest packet
- * @param request The CertificateRequest instance
- * @return the JSON file as the response data content
- */
- JsonSection
- handleChallengeRequest(const Interest& interest, CertificateRequest& request);
+ virtual void
+ handleChallengeRequest(const JsonSection& params, CertificateRequest& request) = 0;
// For Client
- /**
- * @brief Get requirements for requester before sending SELECT interest.
- * @note Should be used by Client Module
- *
- * Before requester sends a USE interest, client should invoke the function to
- * get input instruction and expose the instruction to requester.
- *
- * Every item in the return list requires a input from requester. The item itself is
- * an instruction for requester.
- *
- * @return the input instruction for requester
- */
- std::list<std::string>
- getRequirementForSelect();
-
- /**
- * @brief Get requirements for requester before sending VALIDATE interest.
- * @note Should be used by Client Module
- *
- * Before requester sends a POLL interest, client should invoke the function to
- * get input instruction and expose the instruction to requester.
- *
- * Every item in the return list requires a input from requester. The item itself is
- * an instruction for requester.
- *
- * @param status of the challenge
- * @return the input instruction for requester
- */
- std::list<std::string>
- getRequirementForValidate(const std::string& status);
-
- /**
- * @brief Generate ChallengeInfo part for SELECT interest.
- * @note Should be used by Client Module
- *
- * After requester provides required information, client should invoke the function to
- * generate the ChallengeInfo part of the interest.
- *
- * @param status of the challenge
- * @param paramList contains all the input from requester
- * @return the JSON file of ChallengeInfo
- */
- JsonSection
- genSelectParamsJson(const std::string& status, const std::list<std::string>& paramList);
-
- /**
- * @brief Generate ChallengeInfo part for VALIDATE interest.
- * @note Should be used by Client Module
- *
- * After requester provides required information, client should invoke the function to
- * generate the ChallengeInfo part of the interest.
- *
- * @param status of the challenge
- * @param paramList contains all the input from requester
- * @return the JSON file of ChallengeInfo
- */
- JsonSection
- genValidateParamsJson(const std::string& status, const std::list<std::string>& paramList);
-
-PUBLIC_WITH_TESTS_ELSE_PROTECTED:
- // For CA
virtual JsonSection
- processSelectInterest(const Interest& interest, CertificateRequest& request) = 0;
+ getRequirementForChallenge(int status, const std::string& challengeStatus) = 0;
virtual JsonSection
- processValidateInterest(const Interest& interest, CertificateRequest& request) = 0;
+ genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) = 0;
- virtual JsonSection
- processStatusInterest(const Interest& interest, const CertificateRequest& request);
-
- // For Client
- virtual std::list<std::string>
- getSelectRequirements() = 0;
-
- virtual std::list<std::string>
- getValidateRequirements(const std::string& status) = 0;
-
- virtual JsonSection
- doGenSelectParamsJson(const std::string& status, const std::list<std::string>& paramList) = 0;
-
- virtual JsonSection
- doGenValidateParamsJson(const std::string& status, const std::list<std::string>& paramList) = 0;
-
- // Helpers
- static JsonSection
- getJsonFromNameComponent(const Name& name, int pos);
-
- static Name
- genDownloadName(const Name& caName, const std::string& requestId);
-
+ // helpers
static std::string
generateSecretCode();
+protected:
+
+ void
+ updateRequestOnChallengeEnd(CertificateRequest& request);
+
public:
const std::string CHALLENGE_TYPE;
- static const std::string WAIT_SELECTION;
- static const std::string SUCCESS;
- static const std::string PENDING;
- static const std::string FAILURE;
private:
typedef function<unique_ptr<ChallengeModule> ()> ChallengeCreateFunc;
diff --git a/src/challenge-module/challenge-credential.cpp b/src/challenge-module/challenge-credential.cpp
index 2a47e7a..839ccae 100644
--- a/src/challenge-module/challenge-credential.cpp
+++ b/src/challenge-module/challenge-credential.cpp
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -29,9 +29,9 @@
NDNCERT_REGISTER_CHALLENGE(ChallengeCredential, "Credential");
-const std::string ChallengeCredential::FAILURE_INVALID_FORMAT = "failure-invalid-format";
+const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_CREDENTIAL = "failure-cannot-parse-credential";
+const std::string ChallengeCredential::FAILURE_INVALID_FORMAT_SELF_SIGNED = "failure-cannot-parse-self-signed";
const std::string ChallengeCredential::FAILURE_INVALID_CREDENTIAL = "failure-invalid-credential";
-
const std::string ChallengeCredential::JSON_CREDENTIAL_CERT = "issued-cert";
const std::string ChallengeCredential::JSON_CREDENTIAL_SELF = "self-signed";
@@ -71,101 +71,91 @@
}
}
-JsonSection
-ChallengeCredential::processSelectInterest(const Interest& interest, CertificateRequest& request)
+// For CA
+void
+ChallengeCredential::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
{
if (m_trustAnchors.empty()) {
parseConfigFile();
}
-
- // interest format: /caName/CA/_SELECT/{"request-id":"id"}/CREDENTIAL/{"credential":"..."}/<signature>
- request.setChallengeType(CHALLENGE_TYPE);
- JsonSection credentialJson = getJsonFromNameComponent(interest.getName(), request.getCaName().size() + 4);
-
- // load credential parameters
- std::istringstream ss1(credentialJson.get<std::string>(JSON_CREDENTIAL_CERT));
+ // load credential parameter
+ std::istringstream ss1(params.get<std::string>(JSON_CREDENTIAL_CERT));
security::v2::Certificate cert;
try {
cert = *(io::load<security::v2::Certificate>(ss1));
}
catch (const std::exception& e) {
- _LOG_TRACE("Cannot load credential parameter: cert" << e.what());
- request.setStatus(FAILURE_INVALID_FORMAT);
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_INVALID_FORMAT);
+ _LOG_ERROR("Cannot load credential parameter: cert" << e.what());
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_FORMAT_CREDENTIAL;
+ updateRequestOnChallengeEnd(request);
+ return;
}
ss1.str("");
ss1.clear();
-
- std::istringstream ss2(credentialJson.get<std::string>(JSON_CREDENTIAL_SELF));
- security::v2::Certificate self;
+ // load self-signed data
+ std::istringstream ss2(params.get<std::string>(JSON_CREDENTIAL_SELF));
+ Data self;
try {
- self = *(io::load<security::v2::Certificate>(ss2));
+ self = *(io::load<Data>(ss2));
}
catch (const std::exception& e) {
_LOG_TRACE("Cannot load credential parameter: self-signed cert" << e.what());
- request.setStatus(FAILURE_INVALID_FORMAT);
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_INVALID_FORMAT);
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
+ updateRequestOnChallengeEnd(request);
+ return;
}
ss2.str("");
ss2.clear();
- // verify two parameters
+ // verify the credential and the self-signed cert
Name signingKeyName = cert.getSignature().getKeyLocator().getName();
for (auto anchor : m_trustAnchors) {
if (anchor.getKeyName() == signingKeyName) {
- if (security::verifySignature(cert, anchor) && security::verifySignature(self, cert)) {
- request.setStatus(SUCCESS);
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, SUCCESS);
+ if (security::verifySignature(cert, anchor) && security::verifySignature(self, cert)
+ && readString(self.getContent()) == request.m_requestId) {
+ request.m_status = STATUS_PENDING;
+ request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
+ updateRequestOnChallengeEnd(request);
+ return;
}
}
}
- request.setStatus(FAILURE_INVALID_CREDENTIAL);
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE_INVALID_CREDENTIAL);
+ _LOG_TRACE("Cannot verify the credential + self-signed Data + data content");
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_CREDENTIAL;
+ updateRequestOnChallengeEnd(request);
+ return;
}
+// For Client
JsonSection
-ChallengeCredential::processValidateInterest(const Interest& interest, CertificateRequest& request)
-{
- // there is no validate request here, do nothing
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_INVALID_FORMAT);
-}
-
-std::list<std::string>
-ChallengeCredential::getSelectRequirements()
-{
- std::list<std::string> result;
- result.push_back("Please input the bytes of a certificate issued by the trusted CA");
- result.push_back("Please input the bytes of a self-signed certificate for the corresponding key");
- return result;
-}
-
-std::list<std::string>
-ChallengeCredential::getValidateRequirements(const std::string& status)
-{
- // there is no validate request here, do nothing
- std::list<std::string> result;
- return result;
-}
-
-JsonSection
-ChallengeCredential::doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
+ChallengeCredential::getRequirementForChallenge(int status, const std::string& challengeStatus)
{
JsonSection result;
- BOOST_ASSERT(status == WAIT_SELECTION);
- BOOST_ASSERT(paramList.size() == 2);
- result.put(JSON_CREDENTIAL_CERT, paramList.front());
- result.put(JSON_CREDENTIAL_SELF, paramList.back());
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_CREDENTIAL_CERT, "Please_copy_anchor_signed_cert_here");
+ result.put(JSON_CREDENTIAL_SELF, "Please_copy_key_signed_request_id_data_here");
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
return result;
}
JsonSection
-ChallengeCredential::doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
+ChallengeCredential::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
{
JsonSection result;
- BOOST_ASSERT(paramList.size() == 0);
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_CREDENTIAL_CERT, params.get<std::string>(JSON_CREDENTIAL_CERT, ""));
+ result.put(JSON_CREDENTIAL_SELF, params.get<std::string>(JSON_CREDENTIAL_SELF, ""));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
return result;
}
diff --git a/src/challenge-module/challenge-credential.hpp b/src/challenge-module/challenge-credential.hpp
index bcd8b5d..5d4a93c 100644
--- a/src/challenge-module/challenge-credential.hpp
+++ b/src/challenge-module/challenge-credential.hpp
@@ -1,5 +1,5 @@
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -29,16 +29,17 @@
* @brief Provide Credential based challenge
*
* Credential here means the certificate issued by a trust anchor. Once the requester
- * could proof his/her possession of an existing certificate from other certificate, th
- * requester could finish the challenge.
+ * could proof his/her possession of an existing certificate from other certificate issuer,
+ * the requester could finish the challenge.
*
* The requester needs to provide the proof of the possession of a certificate issued by
* a trust anchor. The challenge require the requester to pass the BASE64 certificate and
- * a BASE64 self-signed certificate whose key is the same as the key in certificate.
+ * a BASE64 Data packet signed by the credential pub key and whose content is the request id.
*
* The main process of this challenge module is:
* 1. Requester provides a certificate signed by that trusted certificate as credential.
* 2. The challenge module will verify the signature of the credential.
+ * 3. The content of the signed Data is the request id
*
* Failure info when application fails:
* FAILURE_INVALID_CREDENTIAL: When the cert issued from trust anchor or self-signed cert
@@ -50,26 +51,16 @@
public:
ChallengeCredential(const std::string& configPath = "");
-PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ // For CA
+ void
+ handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+
+ // For Client
JsonSection
- processSelectInterest(const Interest& interest, CertificateRequest& request) override;
+ getRequirementForChallenge(int status, const std::string& challengeStatus) override;
JsonSection
- processValidateInterest(const Interest& interest, CertificateRequest& request) override;
-
- std::list<std::string>
- getSelectRequirements() override;
-
- std::list<std::string>
- getValidateRequirements(const std::string& status) override;
-
- JsonSection
- doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
-
- JsonSection
- doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
+ genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
@@ -77,8 +68,8 @@
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static const std::string FAILURE_INVALID_CREDENTIAL;
- static const std::string FAILURE_INVALID_FORMAT;
-
+ static const std::string FAILURE_INVALID_FORMAT_CREDENTIAL;
+ static const std::string FAILURE_INVALID_FORMAT_SELF_SIGNED;
static const std::string JSON_CREDENTIAL_CERT;
static const std::string JSON_CREDENTIAL_SELF;
diff --git a/src/challenge-module/challenge-email.cpp b/src/challenge-module/challenge-email.cpp
index b65d331..dbd3b2c 100644
--- a/src/challenge-module/challenge-email.cpp
+++ b/src/challenge-module/challenge-email.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -31,15 +31,9 @@
const std::string ChallengeEmail::NEED_CODE = "need-code";
const std::string ChallengeEmail::WRONG_CODE = "wrong-code";
-
const std::string ChallengeEmail::FAILURE_INVALID_EMAIL = "failure-invalid-email";
-const std::string ChallengeEmail::FAILURE_TIMEOUT = "timeout";
-const std::string ChallengeEmail::FAILURE_MAXRETRY = "max-retry";
-
const std::string ChallengeEmail::JSON_EMAIL = "email";
-const std::string ChallengeEmail::JSON_CODE_TP = "code-timepoint";
const std::string ChallengeEmail::JSON_CODE = "code";
-const std::string ChallengeEmail::JSON_ATTEMPT_TIMES = "attempt-times";
ChallengeEmail::ChallengeEmail(const std::string& scriptPath,
const size_t& maxAttemptTimes,
@@ -51,131 +45,123 @@
{
}
-JsonSection
-ChallengeEmail::processSelectInterest(const Interest& interest, CertificateRequest& request)
+// For CA
+void
+ChallengeEmail::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
{
- // interest format: /caName/CA/_SELECT/{"request-id":"id"}/EMAIL/{"Email":"email"}/<signature>
- JsonSection emailJson = getJsonFromNameComponent(interest.getName(),
- request.getCaName().size() + 4);
- std::string emailAddress = emailJson.get<std::string>(JSON_EMAIL);
- if (!isValidEmailAddress(emailAddress)) {
- request.setStatus(FAILURE_INVALID_EMAIL);
- request.setChallengeType(CHALLENGE_TYPE);
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_INVALID_EMAIL);
+ if (request.m_challengeStatus == "") {
+ // for the first time, init the challenge
+ std::string emailAddress = params.get<std::string>(JSON_EMAIL);
+ if (!isValidEmailAddress(emailAddress)) {
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = FAILURE_INVALID_EMAIL;
+ return;
+ }
+ request.m_status = STATUS_CHALLENGE;
+ request.m_challengeStatus = NEED_CODE;
+ request.m_challengeType = CHALLENGE_TYPE;
+ std::string emailCode = generateSecretCode();
+ JsonSection secretJson;
+ secretJson.add(JSON_CODE, emailCode);
+ request.m_challengeSecrets = secretJson;
+ request.m_challengeTp = time::toIsoString(time::system_clock::now());
+ request.m_remainingTime = m_secretLifetime.count();
+ request.m_remainingTries = m_maxAttemptTimes;
+ // send out the email
+ sendEmail(emailAddress, emailCode, request);
+ _LOG_TRACE("Secret for request " << request.m_requestId << " : " << emailCode);
+ return;
}
-
- std::string emailCode = generateSecretCode();
- sendEmail(emailAddress, emailCode, request.getCaName().toUri());
-
- request.setStatus(NEED_CODE);
- request.setChallengeType(CHALLENGE_TYPE);
- request.setChallengeSecrets(generateStoredSecrets(time::system_clock::now(),
- emailCode, m_maxAttemptTimes));
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, NEED_CODE);
-}
-
-JsonSection
-ChallengeEmail::processValidateInterest(const Interest& interest, CertificateRequest& request)
-{
- // interest format: /caName/CA/_VALIDATION/{"request-id":"id"}/EMAIL/{"code":"code"}/<signature>
- JsonSection infoJson = getJsonFromNameComponent(interest.getName(), request.getCaName().size() + 4);
- std::string givenCode = infoJson.get<std::string>(JSON_CODE);
-
- const auto parsedSecret = parseStoredSecrets(request.getChallengeSecrets());
- if (time::system_clock::now() - std::get<0>(parsedSecret) >= m_secretLifetime) {
- // secret expires
- request.setStatus(FAILURE_TIMEOUT);
- request.setChallengeSecrets(JsonSection());
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_TIMEOUT);
- }
- else if (givenCode == std::get<1>(parsedSecret)) {
- request.setStatus(SUCCESS);
- request.setChallengeSecrets(JsonSection());
- Name downloadName = genDownloadName(request.getCaName(), request.getRequestId());
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, SUCCESS, downloadName);
- }
- else {
- // check rest attempt times
- if (std::get<2>(parsedSecret) > 1) {
- int restAttemptTimes = std::get<2>(parsedSecret) - 1;
- request.setStatus(WRONG_CODE);
- request.setChallengeSecrets(generateStoredSecrets(std::get<0>(parsedSecret),
- std::get<1>(parsedSecret),
- restAttemptTimes));
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, WRONG_CODE);
+ else if (request.m_challengeStatus == NEED_CODE || request.m_challengeStatus == WRONG_CODE) {
+ _LOG_TRACE("Challenge Interest arrives. Challenge Status: " << request.m_challengeStatus);
+ // the incoming interest should bring the pin code
+ std::string givenCode = params.get<std::string>(JSON_CODE);
+ const auto realCode = request.m_challengeSecrets.get<std::string>(JSON_CODE);
+ if (time::system_clock::now() - time::fromIsoString(request.m_challengeTp) >= m_secretLifetime) {
+ // secret expires
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_TIMEOUT;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("Secret expired. Challenge failed.");
+ return;
+ }
+ else if (givenCode == realCode) {
+ // the code is correct
+ request.m_status = STATUS_PENDING;
+ request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("Secret code matched. Challenge succeeded.");
+ return;
}
else {
- // run out times
- request.setStatus(FAILURE_MAXRETRY);
- request.setChallengeSecrets(JsonSection());
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_MAXRETRY);
+ // check rest attempt times
+ if (request.m_remainingTries > 1) {
+ request.m_challengeStatus = WRONG_CODE;
+ request.m_remainingTries = request.m_remainingTries - 1;
+ auto remainTime = m_secretLifetime - (time::system_clock::now() - time::fromIsoString(request.m_challengeTp));
+ request.m_remainingTime = remainTime.count();
+ _LOG_TRACE("Secret code didn't match. Remaining Tries - 1.");
+ return;
+ }
+ else {
+ // run out times
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_MAXRETRY;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("Secret code didn't match. Ran out tires. Challenge failed.");
+ return;
+ }
}
}
-}
-
-std::list<std::string>
-ChallengeEmail::getSelectRequirements()
-{
- std::list<std::string> result;
- result.push_back("Please input your email address:");
- return result;
-}
-
-std::list<std::string>
-ChallengeEmail::getValidateRequirements(const std::string& status)
-{
- std::list<std::string> result;
- if (status == NEED_CODE) {
- result.push_back("Please input your verification code:");
+ else {
+ _LOG_ERROR("The challenge status is wrong");
+ request.m_status = STATUS_FAILURE;
+ return;
}
- else if (status == WRONG_CODE) {
- result.push_back("Incorrect PIN code, please try again and input your verification code:");
+}
+
+// For Client
+JsonSection
+ChallengeEmail::getRequirementForChallenge(int status, const std::string& challengeStatus)
+{
+ JsonSection result;
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_EMAIL, "Please_input_your_email_address");
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ result.put(JSON_CODE, "Please_input_your_verification_code");
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ result.put(JSON_CODE, "Incorrect_code_please_try_again");
+ }
+ else {
+ _LOG_ERROR("CA's status and challenge status are wrong");
}
return result;
}
JsonSection
-ChallengeEmail::doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
+ChallengeEmail::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
{
JsonSection result;
- BOOST_ASSERT(status == WAIT_SELECTION);
- BOOST_ASSERT(paramList.size() == 1);
- result.put(JSON_EMAIL, paramList.front());
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_EMAIL, params.get<std::string>(JSON_EMAIL, ""));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_CODE, params.get<std::string>(JSON_CODE, ""));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_CODE, params.get<std::string>(JSON_CODE, ""));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
return result;
}
-JsonSection
-ChallengeEmail::doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
-{
- JsonSection result;
- BOOST_ASSERT(paramList.size() == 1);
- result.put(JSON_CODE, paramList.front());
- return result;
-}
-
-std::tuple<time::system_clock::TimePoint, std::string, int>
-ChallengeEmail::parseStoredSecrets(const JsonSection& storedSecrets)
-{
- auto tp = time::fromIsoString(storedSecrets.get<std::string>(JSON_CODE_TP));
- std::string rightCode= storedSecrets.get<std::string>(JSON_CODE);
- int attemptTimes = std::stoi(storedSecrets.get<std::string>(JSON_ATTEMPT_TIMES));
-
- return std::make_tuple(tp, rightCode, attemptTimes);
-}
-
-JsonSection
-ChallengeEmail::generateStoredSecrets(const time::system_clock::TimePoint& tp,
- const std::string& secretCode, int attempTimes)
-{
- JsonSection json;
- json.put(JSON_CODE_TP, time::toIsoString(tp));
- json.put(JSON_CODE, secretCode);
- json.put(JSON_ATTEMPT_TIMES, std::to_string(attempTimes));
- return json;
-}
-
bool
ChallengeEmail::isValidEmailAddress(const std::string& emailAddress)
{
@@ -186,10 +172,10 @@
void
ChallengeEmail::sendEmail(const std::string& emailAddress, const std::string& secret,
- const std::string& caName) const
+ const CertificateRequest& request) const
{
std::string command = m_sendEmailScript;
- command += " \"" + emailAddress + "\" \"" + secret + "\" \"" + caName + "\"";
+ command += " \"" + emailAddress + "\" \"" + secret + "\" \"" + request.m_caName.toUri() + "\"";
int result = system(command.c_str());
if (result == -1) {
_LOG_TRACE("EmailSending Script " + m_sendEmailScript + " fails.");
diff --git a/src/challenge-module/challenge-email.hpp b/src/challenge-module/challenge-email.hpp
index a014d00..2f40f1f 100644
--- a/src/challenge-module/challenge-email.hpp
+++ b/src/challenge-module/challenge-email.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -56,26 +56,16 @@
const size_t& maxAttemptTimes = 3,
const time::seconds secretLifetime = time::minutes(20));
-PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ // For CA
+ void
+ handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+
+ // For Client
JsonSection
- processSelectInterest(const Interest& interest, CertificateRequest& request) override;
+ getRequirementForChallenge(int status, const std::string& challengeStatus) override;
JsonSection
- processValidateInterest(const Interest& interest, CertificateRequest& request) override;
-
- std::list<std::string>
- getSelectRequirements() override;
-
- std::list<std::string>
- getValidateRequirements(const std::string& status) override;
-
- JsonSection
- doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
-
- JsonSection
- doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
+ genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static bool
@@ -83,28 +73,16 @@
void
sendEmail(const std::string& emailAddress, const std::string& secret,
- const std::string& caName) const;
+ const CertificateRequest& request) const;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
- static std::tuple<time::system_clock::TimePoint, std::string, int>
- parseStoredSecrets(const JsonSection& storedSecret);
-
- static JsonSection
- generateStoredSecrets(const time::system_clock::TimePoint& tp, const std::string& secretCode,
- int attempTimes);
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ // challenge status
static const std::string NEED_CODE;
static const std::string WRONG_CODE;
-
- static const std::string FAILURE_TIMEOUT;
static const std::string FAILURE_INVALID_EMAIL;
- static const std::string FAILURE_MAXRETRY;
-
+ // JSON attribute
static const std::string JSON_EMAIL;
- static const std::string JSON_CODE_TP;
static const std::string JSON_CODE;
- static const std::string JSON_ATTEMPT_TIMES;
private:
std::string m_sendEmailScript;
diff --git a/src/challenge-module/challenge-pin.cpp b/src/challenge-module/challenge-pin.cpp
index 2bb81ea..7de32f0 100644
--- a/src/challenge-module/challenge-pin.cpp
+++ b/src/challenge-module/challenge-pin.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -20,7 +20,6 @@
#include "challenge-pin.hpp"
#include "logging.hpp"
-#include "json-helper.hpp"
#include <ndn-cxx/util/random.hpp>
namespace ndn {
@@ -32,13 +31,7 @@
const std::string ChallengePin::NEED_CODE = "need-code";
const std::string ChallengePin::WRONG_CODE = "wrong-code";
-
-const std::string ChallengePin::FAILURE_TIMEOUT = "failure-timeout";
-const std::string ChallengePin::FAILURE_MAXRETRY = "failure-max-retry";
-
-const std::string ChallengePin::JSON_CODE_TP = "code-timepoint";
-const std::string ChallengePin::JSON_PIN_CODE = "code";
-const std::string ChallengePin::JSON_ATTEMPT_TIMES = "attempt-times";
+const std::string ChallengePin::JSON_PIN_CODE = "pin-code";
ChallengePin::ChallengePin(const size_t& maxAttemptTimes, const time::seconds& secretLifetime)
: ChallengeModule("PIN")
@@ -47,119 +40,115 @@
{
}
-JsonSection
-ChallengePin::processSelectInterest(const Interest& interest, CertificateRequest& request)
+// For CA
+void
+ChallengePin::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
{
- // interest format: /caName/CA/_SELECT/{"request-id":"id"}/PIN/<signature>
- request.setStatus(NEED_CODE);
- request.setChallengeType(CHALLENGE_TYPE);
- std::string secretCode = generateSecretCode();
- request.setChallengeSecrets(generateStoredSecrets(time::system_clock::now(),
- secretCode,
- m_maxAttemptTimes));
- _LOG_TRACE("Secret for request " << request.getRequestId() << " : " << secretCode);
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, NEED_CODE);
-}
-
-JsonSection
-ChallengePin::processValidateInterest(const Interest& interest, CertificateRequest& request)
-{
- // interest format: /caName/CA/_VALIDATION/{"request-id":"id"}/PIN/{"code":"code"}/<signature>
- JsonSection infoJson = getJsonFromNameComponent(interest.getName(), request.getCaName().size() + 4);
- std::string givenCode = infoJson.get<std::string>(JSON_PIN_CODE);
-
- const auto parsedSecret = parseStoredSecrets(request.getChallengeSecrets());
- if (time::system_clock::now() - std::get<0>(parsedSecret) >= m_secretLifetime) {
- // secret expires
- request.setStatus(FAILURE_TIMEOUT);
- request.setChallengeSecrets(JsonSection());
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_TIMEOUT);
+ if (request.m_challengeStatus == "") {
+ _LOG_TRACE("Challenge Interest arrives. Init the challenge");
+ // for the first time, init the challenge
+ request.m_status = STATUS_CHALLENGE;
+ request.m_challengeStatus = NEED_CODE;
+ request.m_challengeType = CHALLENGE_TYPE;
+ std::string secretCode = generateSecretCode();
+ JsonSection secretJson;
+ secretJson.add(JSON_PIN_CODE, secretCode);
+ request.m_challengeSecrets = secretJson;
+ request.m_challengeTp = time::toIsoString(time::system_clock::now());
+ request.m_remainingTime = m_secretLifetime.count();
+ request.m_remainingTries = m_maxAttemptTimes;
+ _LOG_TRACE("Secret for request " << request.m_requestId << " : " << secretCode);
+ return;
}
- else if (givenCode == std::get<1>(parsedSecret)) {
- request.setStatus(SUCCESS);
- request.setChallengeSecrets(JsonSection());
- Name downloadName = genDownloadName(request.getCaName(), request.getRequestId());
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, SUCCESS, downloadName);
- }
- else {
- // check rest attempt times
- if (std::get<2>(parsedSecret) > 1) {
- int restAttemptTimes = std::get<2>(parsedSecret) - 1;
- request.setStatus(WRONG_CODE);
- request.setChallengeSecrets(generateStoredSecrets(std::get<0>(parsedSecret),
- std::get<1>(parsedSecret),
- restAttemptTimes));
- return genResponseChallengeJson(request.getRequestId(), CHALLENGE_TYPE, WRONG_CODE);
+ else if (request.m_challengeStatus == NEED_CODE || request.m_challengeStatus == WRONG_CODE) {
+ _LOG_TRACE("Challenge Interest arrives. Challenge Status: " << request.m_challengeStatus);
+ // the incoming interest should bring the pin code
+ std::string givenCode = params.get<std::string>(JSON_PIN_CODE);
+ const auto realCode = request.m_challengeSecrets.get<std::string>(JSON_PIN_CODE);
+ if (time::system_clock::now() - time::fromIsoString(request.m_challengeTp) >= m_secretLifetime) {
+ // secret expires
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_TIMEOUT;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("Secret expired. Challenge failed.");
+ return;
+ }
+ else if (givenCode == realCode) {
+ // the code is correct
+ request.m_status = STATUS_PENDING;
+ request.m_challengeStatus = CHALLENGE_STATUS_SUCCESS;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("PIN code matched. Challenge succeeded.");
+ return;
}
else {
- // run out times
- request.setStatus(FAILURE_MAXRETRY);
- request.setChallengeSecrets(JsonSection());
- return genFailureJson(request.getRequestId(), CHALLENGE_TYPE, FAILURE, FAILURE_MAXRETRY);
+ // check rest attempt times
+ if (request.m_remainingTries > 1) {
+ request.m_challengeStatus = WRONG_CODE;
+ request.m_remainingTries = request.m_remainingTries - 1;
+ auto remainTime = m_secretLifetime - (time::system_clock::now() - time::fromIsoString(request.m_challengeTp));
+ request.m_remainingTime = remainTime.count();
+ _LOG_TRACE("PIN code didn't match. Remaining Tries - 1.");
+ return;
+ }
+ else {
+ // run out times
+ request.m_status = STATUS_FAILURE;
+ request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_MAXRETRY;
+ updateRequestOnChallengeEnd(request);
+ _LOG_TRACE("PIN code didn't match. Ran out tires. Challenge failed.");
+ return;
+ }
}
}
-}
-
-std::list<std::string>
-ChallengePin::getSelectRequirements()
-{
- std::list<std::string> result;
- return result;
-}
-
-std::list<std::string>
-ChallengePin::getValidateRequirements(const std::string& status)
-{
- std::list<std::string> result;
- if (status == NEED_CODE) {
- result.push_back("Please input your verification code:");
+ else {
+ _LOG_ERROR("The challenge status is wrong");
+ request.m_status = STATUS_FAILURE;
+ return;
}
- else if (status == WRONG_CODE) {
- result.push_back("Incorrect PIN code, please try again and input your verification code:");
+}
+
+// For Client
+JsonSection
+ChallengePin::getRequirementForChallenge(int status, const std::string& challengeStatus)
+{
+ JsonSection result;
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ // do nothing
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ result.put(JSON_PIN_CODE, "Please_input_your_verification_code");
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ result.put(JSON_PIN_CODE, "Incorrect_PIN_code_please_try_again");
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
}
return result;
}
JsonSection
-ChallengePin::doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
+ChallengePin::genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params)
{
JsonSection result;
- BOOST_ASSERT(status == WAIT_SELECTION);
- BOOST_ASSERT(paramList.size() == 0);
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ // do nothing
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_PIN_CODE, params.get<std::string>(JSON_PIN_CODE, ""));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
+ result.put(JSON_PIN_CODE, params.get<std::string>(JSON_PIN_CODE, ""));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
return result;
}
-JsonSection
-ChallengePin::doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList)
-{
- JsonSection result;
- BOOST_ASSERT(paramList.size() == 1);
- result.put(JSON_PIN_CODE, paramList.front());
- return result;
-}
-
-std::tuple<time::system_clock::TimePoint, std::string, int>
-ChallengePin::parseStoredSecrets(const JsonSection& storedSecrets)
-{
- auto tp = time::fromIsoString(storedSecrets.get<std::string>(JSON_CODE_TP));
- std::string rightCode= storedSecrets.get<std::string>(JSON_PIN_CODE);
- int attemptTimes = std::stoi(storedSecrets.get<std::string>(JSON_ATTEMPT_TIMES));
-
- return std::make_tuple(tp, rightCode, attemptTimes);
-}
-
-JsonSection
-ChallengePin::generateStoredSecrets(const time::system_clock::TimePoint& tp,
- const std::string& secretCode, int attempTimes)
-{
- JsonSection json;
- json.put(JSON_CODE_TP, time::toIsoString(tp));
- json.put(JSON_PIN_CODE, secretCode);
- json.put(JSON_ATTEMPT_TIMES, std::to_string(attempTimes));
- return json;
-}
-
} // namespace ndncert
} // namespace ndn
diff --git a/src/challenge-module/challenge-pin.hpp b/src/challenge-module/challenge-pin.hpp
index 982ed4e..8eef944 100644
--- a/src/challenge-module/challenge-pin.hpp
+++ b/src/challenge-module/challenge-pin.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -51,45 +51,23 @@
ChallengePin(const size_t& maxAttemptTimes = 3,
const time::seconds& secretLifetime = time::seconds(3600));
-PUBLIC_WITH_TESTS_ELSE_PROTECTED:
+ // For CA
+ void
+ handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+
+ // For Client
JsonSection
- processSelectInterest(const Interest& interest, CertificateRequest& request) override;
+ getRequirementForChallenge(int status, const std::string& challengeStatus) override;
JsonSection
- processValidateInterest(const Interest& interest, CertificateRequest& request) override;
-
- std::list<std::string>
- getSelectRequirements() override;
-
- std::list<std::string>
- getValidateRequirements(const std::string& status) override;
-
- JsonSection
- doGenSelectParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
-
- JsonSection
- doGenValidateParamsJson(const std::string& status,
- const std::list<std::string>& paramList) override;
+ genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
- static std::tuple<time::system_clock::TimePoint, std::string, int>
- parseStoredSecrets(const JsonSection& storedSecret);
-
- static JsonSection
- generateStoredSecrets(const time::system_clock::TimePoint& tp, const std::string& secretCode,
- int attempTimes);
-
-PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ // challenge status
static const std::string NEED_CODE;
static const std::string WRONG_CODE;
-
- static const std::string FAILURE_TIMEOUT;
- static const std::string FAILURE_MAXRETRY;
-
- static const std::string JSON_CODE_TP;
+ // JSON attribute
static const std::string JSON_PIN_CODE;
- static const std::string JSON_ATTEMPT_TIMES;
private:
time::seconds m_secretLifetime;
diff --git a/src/client-config.cpp b/src/client-config.cpp
index e28407c..47b75da 100644
--- a/src/client-config.cpp
+++ b/src/client-config.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -61,19 +61,9 @@
ClientCaItem item;
item.m_caName = Name(configSection.get<std::string>("ca-prefix"));
item.m_caInfo = configSection.get<std::string>("ca-info");
- item.m_probe = configSection.get("probe", "");
- std::string listEnabledField = configSection.get("is-list-enabled", "false");
- if (listEnabledField == "true") {
- item.m_isListEnabled = true;
- }
- else {
- item.m_isListEnabled = false;
- }
- item.m_targetedList = configSection.get("target-list", "");
-
+ item.m_probe = configSection.get<std::string>("probe");
std::istringstream ss(configSection.get<std::string>("certificate"));
item.m_anchor = *(io::load<security::v2::Certificate>(ss));
-
return item;
}
diff --git a/src/client-config.hpp b/src/client-config.hpp
index 72dd78f..b3aa0fc 100644
--- a/src/client-config.hpp
+++ b/src/client-config.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -40,10 +40,6 @@
std::string m_caInfo;
// An instruction for requesters to use _PROBE. Extracted from config field "probe"
std::string m_probe;
- // Whether support list function
- bool m_isListEnabled;
- // An instruction for requesters to get a recommended CA. Extracted from config field "target-list"
- std::string m_targetedList;
// CA's certificate
security::v2::Certificate m_anchor;
diff --git a/src/client-module.cpp b/src/client-module.cpp
index 0c9565e..5b03a23 100644
--- a/src/client-module.cpp
+++ b/src/client-module.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -20,511 +20,323 @@
#include "client-module.hpp"
#include "logging.hpp"
-#include "json-helper.hpp"
#include "challenge-module.hpp"
+#include "crypto-support/enc-tlv.hpp"
#include <ndn-cxx/util/io.hpp>
#include <ndn-cxx/security/signing-helpers.hpp>
#include <ndn-cxx/security/verification-helpers.hpp>
+#include <ndn-cxx/util/random.hpp>
+#include <ndn-cxx/security/transform/base64-encode.hpp>
+#include <ndn-cxx/security/transform/buffer-source.hpp>
+#include <ndn-cxx/security/transform/stream-sink.hpp>
namespace ndn {
namespace ndncert {
_LOG_INIT(ndncert.client);
-ClientModule::ClientModule(Face& face, security::v2::KeyChain& keyChain, size_t retryTimes)
- : m_face(face)
- , m_keyChain(keyChain)
- , m_retryTimes(retryTimes)
+ClientModule::ClientModule(security::v2::KeyChain& keyChain)
+ : m_keyChain(keyChain)
{
}
ClientModule::~ClientModule() = default;
-void
-ClientModule::requestCaTrustAnchor(const Name& caName, const DataCallback& trustAnchorCallback,
- const ErrorCallback& errorCallback)
+shared_ptr<Interest>
+ClientModule::generateProbeInfoInterest(const Name& caName)
{
Name interestName = caName;
- interestName.append("CA").append("_DOWNLOAD").append("ANCHOR");
- Interest interest(interestName);
- interest.setMustBeFresh(true);
-
- m_face.expressInterest(interest, trustAnchorCallback,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- trustAnchorCallback, errorCallback));
+ if (readString(caName.at(-1)) != "CA")
+ interestName.append("CA");
+ interestName.append("_PROBE").append("INFO");
+ auto interest = make_shared<Interest>(interestName);
+ interest->setMustBeFresh(true);
+ interest->setCanBePrefix(false);
+ return interest;
}
void
-ClientModule::requestLocalhostList(const LocalhostListCallback& listCallback,
- const ErrorCallback& errorCallback)
+ClientModule::onProbeInfoResponse(const Data& reply)
{
- Interest interest(Name("/localhost/CA/_LIST"));
- interest.setMustBeFresh(true);
- DataCallback dataCb = bind(&ClientModule::handleLocalhostListResponse,
- this, _1, _2, listCallback, errorCallback);
- m_face.expressInterest(interest, dataCb,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- dataCb, errorCallback));
-}
+ // parse the ca item
+ auto contentJson = getJsonFromData(reply);
+ auto caItem = ClientConfig::extractCaItem(contentJson);
-void
-ClientModule::handleLocalhostListResponse(const Interest& request, const Data& reply,
- const LocalhostListCallback& listCallback,
- const ErrorCallback& errorCallback)
-{
- // TODO: use the file path to replace the cert
- // const auto& pib = m_keyChain.getPib();
- // auto identity = pib.getDefaultIdentity();
- // auto key = identity.getDefaultKey();
- // auto cert = key.getDefaultCertificate();
-
- auto cert = *(io::load<security::v2::Certificate>(m_config.m_localNdncertAnchor));
-
- if (!security::verifySignature(reply, cert)) {
- errorCallback("Cannot verify data from localhost CA");
- return;
- };
-
- JsonSection contentJson = getJsonFromData(reply);
- ClientConfig clientConf;
- clientConf.load(contentJson);
- listCallback(clientConf);
-}
-
-void
-ClientModule::requestList(const ClientCaItem& ca, const std::string& additionalInfo,
- const ListCallback& listCallback, const ErrorCallback& errorCallback)
-{
- Name requestName(ca.m_caName);
- requestName.append("_LIST");
- if (additionalInfo != "") {
- requestName.append(additionalInfo);
- }
- Interest interest(requestName);
- interest.setMustBeFresh(true);
- DataCallback dataCb = bind(&ClientModule::handleListResponse,
- this, _1, _2, ca, listCallback, errorCallback);
- m_face.expressInterest(interest, dataCb,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- dataCb, errorCallback));
-}
-
-void
-ClientModule::handleListResponse(const Interest& request, const Data& reply,
- const ClientCaItem& ca,
- const ListCallback& listCallback,
- const ErrorCallback& errorCallback)
-{
- if (!security::verifySignature(reply, ca.m_anchor)) {
- errorCallback("Cannot verify data from " + ca.m_caName.toUri());
- return;
- };
-
- std::list<Name> caList;
- Name assignedName;
-
- JsonSection contentJson = getJsonFromData(reply);
- auto recommendedName = contentJson.get("recommended-identity", "");
- if (recommendedName == "") {
- // without recommendation
- auto caListJson = contentJson.get_child("ca-list");
- auto it = caListJson.begin();
- for(; it != caListJson.end(); it++) {
- caList.push_back(Name(it->second.get<std::string>("ca-prefix")));
+ // update the local config
+ bool findItem = false;
+ for (auto& item : m_config.m_caItems) {
+ if (item.m_caName == caItem.m_caName) {
+ findItem = true;
+ item = caItem;
}
}
- else {
- // with recommendation
- Name caName(contentJson.get<std::string>("recommended-ca"));
- caList.push_back(caName);
- assignedName = caName.append(recommendedName);
+ if (!findItem) {
+ m_config.m_caItems.push_back(caItem);
}
- Name schemaDataName(contentJson.get("trust-schema", ""));
- listCallback(caList, assignedName, schemaDataName);
-}
-void
-ClientModule::sendProbe(const ClientCaItem& ca, const std::string& probeInfo,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
-{
- Interest interest(Name(ca.m_caName).append("_PROBE").append(probeInfo));
- interest.setMustBeFresh(true);
- DataCallback dataCb = bind(&ClientModule::handleProbeResponse,
- this, _1, _2, ca, requestCallback, errorCallback);
- m_face.expressInterest(interest, dataCb,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- dataCb, errorCallback));
-
- _LOG_TRACE("PROBE interest sent with Probe info " << probeInfo);
-}
-
-void
-ClientModule::handleProbeResponse(const Interest& request, const Data& reply,
- const ClientCaItem& ca,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
-{
- if (!security::verifySignature(reply, ca.m_anchor)) {
- errorCallback("Cannot verify data from " + ca.m_caName.toUri());
- return;
- };
- JsonSection contentJson = getJsonFromData(reply);
- std::string identityNameString = contentJson.get(JSON_IDNENTIFIER, "");
- if (!identityNameString.empty()) {
- Name identityName(identityNameString);
- sendNew(ca, identityName, requestCallback, errorCallback);
-
- _LOG_TRACE("Got PROBE response with identity " << identityName);
- }
- else {
- errorCallback("The response does not carry required fields.");
+ // verify the probe Data's sig
+ if (!security::verifySignature(reply, caItem.m_anchor)) {
+ _LOG_ERROR("Cannot verify data signature from " << m_ca.m_caName.toUri());
return;
}
}
-void
-ClientModule::sendNew(const ClientCaItem& ca, const Name& identityName,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
+shared_ptr<Interest>
+ClientModule::generateProbeInterest(const ClientCaItem& ca, const std::string& probeInfo)
{
+ Name interestName = ca.m_caName;
+ interestName.append("CA").append("_PROBE");
+ auto interest = make_shared<Interest>(interestName);
+ interest->setMustBeFresh(true);
+ interest->setCanBePrefix(false);
+ auto paramJson = genProbeRequestJson(probeInfo);
+ interest->setApplicationParameters(paramFromJson(paramJson));
+
+ // update local state
+ m_ca = ca;
+ return interest;
+}
+
+void
+ClientModule::onProbeResponse(const Data& reply)
+{
+ if (!security::verifySignature(reply, m_ca.m_anchor)) {
+ _LOG_ERROR("Cannot verify data signature from " << m_ca.m_caName.toUri());
+ return;
+ }
+ auto contentJson = getJsonFromData(reply);
+
+ // read the available name and put it into the state
+ auto nameUri = contentJson.get<std::string>(JSON_CA_NAME, "");
+ if (nameUri != "") {
+ m_identityName = Name(nameUri);
+ }
+}
+
+shared_ptr<Interest>
+ClientModule::generateNewInterest(const time::system_clock::TimePoint& notBefore,
+ const time::system_clock::TimePoint& notAfter,
+ const Name& identityName)
+{
+ // Name requestedName = identityName;
+ if (!identityName.empty()) { // if identityName is not empty, find the corresponding CA
+ bool findCa = false;
+ for (const auto& caItem : m_config.m_caItems) {
+ if (caItem.m_caName.isPrefixOf(identityName)) {
+ m_ca = caItem;
+ findCa = true;
+ }
+ }
+ if (!findCa) { // if cannot find, cannot proceed
+ return nullptr;
+ }
+ m_identityName = identityName;
+ }
+ else { // if identityName is empty, check m_identityName or generate a random name
+ if (!m_identityName.empty()) {
+ // do nothing
+ }
+ else {
+ auto id = std::to_string(random::generateSecureWord64());
+ m_identityName = m_ca.m_caName;
+ m_identityName.append(id);
+ }
+ }
+
+ // generate a newly key pair or use an existing key
const auto& pib = m_keyChain.getPib();
-
- auto state = make_shared<RequestState>();
try {
- auto identity = pib.getIdentity(identityName);
- state->m_key = m_keyChain.createKey(identity);
+ auto identity = pib.getIdentity(m_identityName);
+ m_key = m_keyChain.createKey(identity);
}
catch (const security::Pib::Error& e) {
- auto identity = m_keyChain.createIdentity(identityName);
- state->m_key = identity.getDefaultKey();
+ auto identity = m_keyChain.createIdentity(m_identityName);
+ m_key = identity.getDefaultKey();
}
- state->m_ca = ca;
- state->m_isInstalled = false;
// generate certificate request
security::v2::Certificate certRequest;
- certRequest.setName(Name(state->m_key.getName()).append("cert-request").appendVersion());
+ certRequest.setName(Name(m_key.getName()).append("cert-request").appendVersion());
certRequest.setContentType(tlv::ContentType_Key);
certRequest.setFreshnessPeriod(time::hours(24));
- certRequest.setContent(state->m_key.getPublicKey().data(), state->m_key.getPublicKey().size());
+ certRequest.setContent(m_key.getPublicKey().data(), m_key.getPublicKey().size());
SignatureInfo signatureInfo;
- signatureInfo.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
- time::system_clock::now() + time::days(10)));
- m_keyChain.sign(certRequest, signingByKey(state->m_key.getName()).setSignatureInfo(signatureInfo));
+ signatureInfo.setValidityPeriod(security::ValidityPeriod(notBefore, notAfter));
+ m_keyChain.sign(certRequest, signingByKey(m_key.getName()).setSignatureInfo(signatureInfo));
- // generate interest
- Interest interest(Name(ca.m_caName).append(Name("_NEW")).append(certRequest.wireEncode()));
- m_keyChain.sign(interest, signingByKey(state->m_key.getName()));
+ // generate Interest packet
+ Name interestName = m_ca.m_caName;
+ interestName.append("CA").append("_NEW");
+ auto interest = make_shared<Interest>(interestName);
+ interest->setMustBeFresh(true);
+ interest->setCanBePrefix(false);
+ interest->setApplicationParameters(paramFromJson(genNewRequestJson(m_ecdh.getBase64PubKey(), certRequest)));
- DataCallback dataCb = bind(&ClientModule::handleNewResponse,
- this, _1, _2, state, requestCallback, errorCallback);
- m_face.expressInterest(interest, dataCb,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- dataCb, errorCallback));
-
- _LOG_TRACE("NEW interest sent with identity " << identityName);
+ // sign the Interest packet
+ m_keyChain.sign(*interest, signingByKey(m_key.getName()));
+ return interest;
}
-void
-ClientModule::handleNewResponse(const Interest& request, const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
+std::list<std::string>
+ClientModule::onNewResponse(const Data& reply)
{
- if (!security::verifySignature(reply, state->m_ca.m_anchor)) {
- errorCallback("Cannot verify data from " + state->m_ca.m_caName.toUri());
- return;
+ if (!security::verifySignature(reply, m_ca.m_anchor)) {
+ _LOG_ERROR("Cannot verify data signature from " << m_ca.m_caName.toUri());
+ return std::list<std::string>();
}
+ auto contentJson = getJsonFromData(reply);
- const JsonSection& json = getJsonFromData(reply);
- state->m_status = json.get(JSON_STATUS, "");
- state->m_requestId = json.get(JSON_REQUEST_ID, "");
+ // ECDH
+ const auto& peerKeyBase64Str = contentJson.get<std::string>(JSON_CA_ECDH, "");
+ const auto& saltStr = contentJson.get<std::string>(JSON_CA_SALT, "");
+ uint64_t saltInt = std::stoull(saltStr);
+ uint8_t salt[sizeof(saltInt)];
+ std::memcpy(salt, &saltInt, sizeof(saltInt));
+ m_ecdh.deriveSecret(peerKeyBase64Str);
- if (!checkStatus(*state, json, errorCallback)) {
- return;
- }
+ // HKDF
+ hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen, salt, sizeof(saltInt), m_aesKey, 32);
- JsonSection challengesJson = json.get_child(JSON_CHALLENGES);
- std::list<std::string> challengeList;
+ // update state
+ m_status = contentJson.get<int>(JSON_CA_STATUS);
+ m_requestId = contentJson.get<std::string>(JSON_CA_EQUEST_ID, "");
+
+ auto challengesJson = contentJson.get_child(JSON_CA_CHALLENGES);
+ m_challengeList.clear();
for (const auto& challengeJson : challengesJson) {
- challengeList.push_back(challengeJson.second.get<std::string>(JSON_CHALLENGE_TYPE));
+ m_challengeList.push_back(challengeJson.second.get<std::string>(JSON_CA_CHALLENGE_ID, ""));
}
- state->m_challengeList = challengeList;
+ return m_challengeList;
+}
- _LOG_TRACE("Got NEW response with requestID " << state->m_requestId
- << " with status " << state->m_status
- << " with challenge number " << challengeList.size());
+shared_ptr<Interest>
+ClientModule::generateChallengeInterest(const JsonSection& paramJson)
+{
+ m_challengeType = paramJson.get<std::string>(JSON_CLIENT_SELECTED_CHALLENGE);
- requestCallback(state);
+ Name interestName = m_ca.m_caName;
+ interestName.append("CA").append("_CHALLENGE").append(m_requestId);
+ auto interest = make_shared<Interest>(interestName);
+ interest->setMustBeFresh(true);
+ interest->setCanBePrefix(false);
+
+ // encrypt the Interest parameters
+ std::stringstream ss;
+ boost::property_tree::write_json(ss, paramJson);
+ auto payload = ss.str();
+ auto paramBlock = genEncBlock(tlv::ApplicationParameters, m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
+ (const uint8_t*)payload.c_str(), payload.size());
+ interest->setApplicationParameters(paramBlock);
+
+ m_keyChain.sign(*interest, signingByKey(m_key.getName()));
+ return interest;
}
void
-ClientModule::sendSelect(const shared_ptr<RequestState>& state,
- const std::string& challengeType,
- const JsonSection& selectParams,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
+ClientModule::onChallengeResponse(const Data& reply)
{
- JsonSection requestIdJson;
- requestIdJson.put(JSON_REQUEST_ID, state->m_requestId);
-
- state->m_challengeType = challengeType;
-
- Name interestName(state->m_ca.m_caName);
- interestName.append("_SELECT")
- .append(nameBlockFromJson(requestIdJson))
- .append(challengeType)
- .append(nameBlockFromJson(selectParams));
- Interest interest(interestName);
- m_keyChain.sign(interest, signingByKey(state->m_key.getName()));
-
- DataCallback dataCb = bind(&ClientModule::handleSelectResponse,
- this, _1, _2, state, requestCallback, errorCallback);
- m_face.expressInterest(interest, dataCb,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- dataCb, errorCallback));
-
- _LOG_TRACE("SELECT interest sent with challenge type " << challengeType);
-}
-
-void
-ClientModule::handleSelectResponse(const Interest& request,
- const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
-{
- if (!security::verifySignature(reply, state->m_ca.m_anchor)) {
- errorCallback("Cannot verify data from " + state->m_ca.m_caName.toUri());
+ if (!security::verifySignature(reply, m_ca.m_anchor)) {
+ _LOG_ERROR("Cannot verify data signature from " << m_ca.m_caName.toUri());
return;
}
+ auto result = parseEncBlock(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen, reply.getContent());
+ std::string payload((const char*)result.data(), result.size());
+ std::istringstream ss(payload);
+ JsonSection contentJson;
+ boost::property_tree::json_parser::read_json(ss, contentJson);
- JsonSection json = getJsonFromData(reply);
+ // update state
+ m_status = contentJson.get<int>(JSON_CA_STATUS);
+ m_challengeStatus = contentJson.get<std::string>(JSON_CHALLENGE_STATUS);
+ m_remainingTries = contentJson.get<int>(JSON_CHALLENGE_REMAINING_TRIES);
+ m_freshBefore = time::system_clock::now() + time::seconds(contentJson.get<int>(JSON_CHALLENGE_REMAINING_TIME));
+}
- _LOG_TRACE("SELECT response would change the status from "
- << state->m_status << " to " + json.get<std::string>(JSON_STATUS));
+shared_ptr<Interest>
+ClientModule::generateDownloadInterest()
+{
+ Name interestName = m_ca.m_caName;
+ interestName.append("CA").append("_DOWNLOAD").append(m_requestId);
+ auto interest = make_shared<Interest>(interestName);
+ interest->setMustBeFresh(true);
+ interest->setCanBePrefix(false);
+ return interest;
+}
- state->m_status = json.get<std::string>(JSON_STATUS);
-
- if (!checkStatus(*state, json, errorCallback)) {
- return;
- }
-
- _LOG_TRACE("Got SELECT response with status " << state->m_status);
-
- requestCallback(state);
+shared_ptr<Interest>
+ClientModule::generateCertFetchInterest()
+{
+ Name interestName = m_identityName;
+ interestName.append("KEY").append(m_certId);
+ auto interest = make_shared<Interest>(interestName);
+ interest->setMustBeFresh(true);
+ interest->setCanBePrefix(false);
+ return interest;
}
void
-ClientModule::sendValidate(const shared_ptr<RequestState>& state,
- const JsonSection& validateParams,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
+ClientModule::onDownloadResponse(const Data& reply)
{
- JsonSection requestIdJson;
- requestIdJson.put(JSON_REQUEST_ID, state->m_requestId);
-
- Name interestName(state->m_ca.m_caName);
- interestName.append("_VALIDATE")
- .append(nameBlockFromJson(requestIdJson))
- .append(state->m_challengeType)
- .append(nameBlockFromJson(validateParams));
- Interest interest(interestName);
- m_keyChain.sign(interest, signingByKey(state->m_key.getName()));
-
- DataCallback dataCb = bind(&ClientModule::handleValidateResponse,
- this, _1, _2, state, requestCallback, errorCallback);
- m_face.expressInterest(interest, dataCb,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- dataCb, errorCallback));
-
- _LOG_TRACE("VALIDATE interest sent");
-}
-
-void
-ClientModule::handleValidateResponse(const Interest& request,
- const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
-{
- if (!security::verifySignature(reply, state->m_ca.m_anchor)) {
- errorCallback("Cannot verify data from " + state->m_ca.m_caName.toUri());
- return;
- }
-
- JsonSection json = getJsonFromData(reply);
- state->m_status = json.get<std::string>(JSON_STATUS);
-
- if (!checkStatus(*state, json, errorCallback)) {
- return;
- }
-
- _LOG_TRACE("Got VALIDATE response with status " << state->m_status);
-
- requestCallback(state);
-}
-
-
-void
-ClientModule::requestStatus(const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
-{
- JsonSection requestIdJson;
- requestIdJson.put(JSON_REQUEST_ID, state->m_requestId);
-
- Name interestName(state->m_ca.m_caName);
- interestName.append("_STATUS").append(nameBlockFromJson(requestIdJson));
- Interest interest(interestName);
-
- m_keyChain.sign(interest, signingByKey(state->m_key.getName()));
-
- DataCallback dataCb = bind(&ClientModule::handleStatusResponse,
- this, _1, _2, state, requestCallback, errorCallback);
- m_face.expressInterest(interest, dataCb,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- dataCb, errorCallback));
-
- _LOG_TRACE("STATUS interest sent");
-}
-
-void
-ClientModule::handleStatusResponse(const Interest& request, const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
-{
- if (!security::verifySignature(reply, state->m_ca.m_anchor)) {
- errorCallback("Cannot verify data from " + state->m_ca.m_caName.toUri());
- return;
- }
-
- JsonSection json = getJsonFromData(reply);
- state->m_status = json.get<std::string>(JSON_STATUS);
-
- if (!checkStatus(*state, json, errorCallback)) {
- return;
- }
-
- _LOG_TRACE("Got STATUS response with status " << state->m_status);
-
- requestCallback(state);
-}
-
-void
-ClientModule::requestDownload(const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
-{
- JsonSection requestIdJson;
- requestIdJson.put(JSON_REQUEST_ID, state->m_requestId);
-
- Name interestName(state->m_ca.m_caName);
- interestName.append("_DOWNLOAD").append(nameBlockFromJson(requestIdJson));
- Interest interest(interestName);
- interest.setMustBeFresh(true);
-
- DataCallback dataCb = bind(&ClientModule::handleDownloadResponse,
- this, _1, _2, state, requestCallback, errorCallback);
- m_face.expressInterest(interest, dataCb,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, m_retryTimes,
- dataCb, errorCallback));
-
- _LOG_TRACE("DOWNLOAD interest sent");
-}
-
-void
-ClientModule::handleDownloadResponse(const Interest& request, const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback)
-{
- if (!security::verifySignature(reply, state->m_ca.m_anchor)) {
- errorCallback("Cannot verify data from " + state->m_ca.m_caName.toUri());
- return;
- }
-
try {
security::v2::Certificate cert(reply.getContent().blockFromValue());
- m_keyChain.addCertificate(state->m_key, cert);
-
+ m_keyChain.addCertificate(m_key, cert);
_LOG_TRACE("Got DOWNLOAD response and installed the cert " << cert.getName());
}
catch (const std::exception& e) {
- errorCallback(std::string(e.what()));
+ _LOG_ERROR("Cannot add replied certificate into the keychain " << e.what());
return;
}
-
- state->m_isInstalled = true;
- requestCallback(state);
+ m_isCertInstalled = true;
}
void
-ClientModule::onTimeout(const Interest& interest, int nRetriesLeft, const DataCallback& dataCallback,
- const ErrorCallback& errorCallback)
+ClientModule::onCertFetchResponse(const Data& reply)
{
- if (nRetriesLeft > 0) {
- m_face.expressInterest(interest, dataCallback,
- bind(&ClientModule::onNack, this, _1, _2, errorCallback),
- bind(&ClientModule::onTimeout, this, _1, nRetriesLeft - 1,
- dataCallback, errorCallback));
- }
- else {
- errorCallback("Run out retries: still timeout");
- return;
- }
-}
-
-void
-ClientModule::onNack(const Interest& interest, const lp::Nack& nack, const ErrorCallback& errorCallback)
-{
- errorCallback("Got Nack");
+ onDownloadResponse(reply);
}
JsonSection
ClientModule::getJsonFromData(const Data& data)
{
- Block jsonBlock = data.getContent();
- std::string jsonString = encoding::readString(jsonBlock);
- std::istringstream ss(jsonString);
+ std::istringstream ss(encoding::readString(data.getContent()));
JsonSection json;
boost::property_tree::json_parser::read_json(ss, json);
return json;
}
+const JsonSection
+ClientModule::genProbeRequestJson(const std::string& probeInfo)
+{
+ JsonSection root;
+ root.put(JSON_CLIENT_PROBE_INFO, probeInfo);
+ return root;
+}
+
+const JsonSection
+ClientModule::genNewRequestJson(const std::string& ecdhPub, const security::v2::Certificate& certRequest)
+{
+ JsonSection root;
+ std::stringstream ss;
+ try {
+ security::transform::bufferSource(certRequest.wireEncode().wire(), certRequest.wireEncode().size())
+ >> security::transform::base64Encode(true)
+ >> security::transform::streamSink(ss);
+ }
+ catch (const security::transform::Error& e) {
+ _LOG_ERROR("Cannot convert self-signed cert into BASE64 string " << e.what());
+ return root;
+ }
+ root.put(JSON_CLIENT_ECDH, ecdhPub);
+ root.put(JSON_CLIENT_CERT_REQ, ss.str());
+ return root;
+}
+
Block
-ClientModule::nameBlockFromJson(const JsonSection& json)
+ClientModule::paramFromJson(const JsonSection& json)
{
std::stringstream ss;
boost::property_tree::write_json(ss, json);
- return makeStringBlock(ndn::tlv::GenericNameComponent, ss.str());
-}
-
-bool
-ClientModule::checkStatus(const RequestState& state, const JsonSection& json,
- const ErrorCallback& errorCallback)
-{
- if (state.m_status == ChallengeModule::FAILURE) {
- errorCallback(json.get(JSON_FAILURE_INFO, ""));
- return false;
- }
- if (state.m_requestId.empty() || state.m_status.empty()) {
- errorCallback("The response does not carry required fields. requestID: " + state.m_requestId
- + " status: " + state.m_status);
- return false;
- }
- return true;
+ return makeStringBlock(ndn::tlv::ApplicationParameters, ss.str());
}
} // namespace ndncert
diff --git a/src/client-module.hpp b/src/client-module.hpp
index df2a43a..bbf124c 100644
--- a/src/client-module.hpp
+++ b/src/client-module.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2018, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -22,26 +22,12 @@
#define NDNCERT_CLIENT_MODULE_HPP
#include "client-config.hpp"
+#include "crypto-support/crypto-helper.hpp"
#include "certificate-request.hpp"
namespace ndn {
namespace ndncert {
-class RequestState
-{
-
-public:
- ClientCaItem m_ca;
- security::Key m_key;
-
- std::string m_requestId;
- std::string m_status;
- std::string m_challengeType;
- std::list<std::string> m_challengeList;
-
- bool m_isInstalled = false;
-};
-
// TODO
// For each CA item in Client.Conf, create a validator instance and initialize it with CA's cert
// The validator instance should be in ClientCaItem
@@ -58,13 +44,8 @@
using std::runtime_error::runtime_error;
};
- using LocalhostListCallback = function<void (const ClientConfig&)>;
- using ListCallback = function<void (const std::list<Name>&, const Name&, const Name&)>;
- using RequestCallback = function<void (const shared_ptr<RequestState>&)>;
- using ErrorCallback = function<void (const std::string&)>;
-
public:
- ClientModule(Face& face, security::v2::KeyChain& keyChain, size_t retryTimes = 2);
+ ClientModule(security::v2::KeyChain& keyChain);
virtual
~ClientModule();
@@ -75,114 +56,97 @@
return m_config;
}
- /**
- * @brief Send /CA-prefix/CA/_DOWNLOAD/ANCHOR to get CA's latest anchor with the config
- */
- void
- requestCaTrustAnchor(const Name& caName, const DataCallback& trustAnchorCallback,
- const ErrorCallback& errorCallback);
+ int
+ getApplicationStatus() const
+ {
+ return m_status;
+ }
+
+ std::string
+ getChallengeStatus() const
+ {
+ return m_challengeStatus;
+ }
+
+ shared_ptr<Interest>
+ generateProbeInfoInterest(const Name& caName);
/**
- * @brief Send /localhost/CA/List to query local available CAs
- *
- * For more information:
- * https://github.com/named-data/ndncert/wiki/Intra-Node-Design
+ * @brief Process the replied PROBE INFO Data packet
+ * Warning: this function will add a new trust anchor into the application.
+ * Please invoke this function only when reply can be fully trusted or the CA
+ * can be verified in later challenge phase.
*/
void
- requestLocalhostList(const LocalhostListCallback& listCallback, const ErrorCallback& errorCallback);
+ onProbeInfoResponse(const Data& reply);
- /**
- * @brief Handle the list request response
- */
- void
- handleLocalhostListResponse(const Interest& request, const Data& reply,
- const LocalhostListCallback& listCallback, const ErrorCallback& errorCallback);
+ shared_ptr<Interest>
+ generateProbeInterest(const ClientCaItem& ca, const std::string& probeInfo);
void
- requestList(const ClientCaItem& ca, const std::string& additionalInfo,
- const ListCallback& listCallback, const ErrorCallback& errorCallback);
+ onProbeResponse(const Data& reply);
+
+ shared_ptr<Interest>
+ generateNewInterest(const time::system_clock::TimePoint& notBefore,
+ const time::system_clock::TimePoint& notAfter,
+ const Name& identityName = Name());
+
+ std::list<std::string>
+ onNewResponse(const Data& reply);
+
+ shared_ptr<Interest>
+ generateChallengeInterest(const JsonSection& paramJson);
void
- handleListResponse(const Interest& request, const Data& reply, const ClientCaItem& ca,
- const ListCallback& listCallback, const ErrorCallback& errorCallback);
+ onChallengeResponse(const Data& reply);
+
+ shared_ptr<Interest>
+ generateDownloadInterest();
+
+ shared_ptr<Interest>
+ generateCertFetchInterest();
void
- sendProbe(const ClientCaItem& ca, const std::string& probeInfo,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
+ onDownloadResponse(const Data& reply);
void
- handleProbeResponse(const Interest& request, const Data& reply, const ClientCaItem& ca,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- sendNew(const ClientCaItem& ca, const Name& identityName,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- handleNewResponse(const Interest& request, const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- sendSelect(const shared_ptr<RequestState>& state, const std::string& challengeType,
- const JsonSection& selectParams,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- handleSelectResponse(const Interest& request, const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- sendValidate(const shared_ptr<RequestState>& state, const JsonSection& validateParams,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- handleValidateResponse(const Interest& request, const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- requestStatus(const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- handleStatusResponse(const Interest& request, const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
-
- void
- requestDownload(const shared_ptr<RequestState>& state, const RequestCallback& requestCallback,
- const ErrorCallback& errorCallback);
-
- void
- handleDownloadResponse(const Interest& request, const Data& reply,
- const shared_ptr<RequestState>& state,
- const RequestCallback& requestCallback, const ErrorCallback& errorCallback);
+ onCertFetchResponse(const Data& reply);
// helper functions
static JsonSection
getJsonFromData(const Data& data);
static Block
- nameBlockFromJson(const JsonSection& json);
+ paramFromJson(const JsonSection& json);
- static bool
- checkStatus(const RequestState& state, const JsonSection& json, const ErrorCallback& errorCallback);
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ const JsonSection
+ genProbeRequestJson(const std::string& probeInfo);
-protected:
- virtual void
- onTimeout(const Interest& interest, int nRetriesLeft,
- const DataCallback& dataCallback, const ErrorCallback& errorCallback);
+ const JsonSection
+ genNewRequestJson(const std::string& ecdhPub, const security::v2::Certificate& certRequest);
- virtual void
- onNack(const Interest& interest, const lp::Nack& nack, const ErrorCallback& errorCallback);
-
-protected:
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
ClientConfig m_config;
- Face& m_face;
security::v2::KeyChain& m_keyChain;
- size_t m_retryTimes;
+
+ ClientCaItem m_ca;
+ security::Key m_key;
+ Name m_identityName;
+
+ std::string m_requestId = "";
+ int m_status = STATUS_NOT_STARTED;
+ std::string m_challengeStatus = "";
+ std::string m_challengeType = "";
+ std::string m_certId = "";
+ std::list<std::string> m_challengeList;
+ bool m_isCertInstalled = false;
+
+ int m_remainingTries = 0;
+ time::system_clock::TimePoint m_freshBefore;
+
+ ECDHState m_ecdh;
+ uint8_t m_aesKey[32] = {0};
};
} // namespace ndncert
diff --git a/src/crypto-support/crypto-helper.cpp b/src/crypto-support/crypto-helper.cpp
new file mode 100644
index 0000000..915f17c
--- /dev/null
+++ b/src/crypto-support/crypto-helper.cpp
@@ -0,0 +1,256 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2019, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "crypto-helper.hpp"
+#include "../logging.hpp"
+#include <openssl/pem.h>
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <ndn-cxx/security/transform/block-cipher.hpp>
+#include <ndn-cxx/security/transform/base64-decode.hpp>
+#include <ndn-cxx/security/transform/base64-encode.hpp>
+#include <ndn-cxx/security/transform/buffer-source.hpp>
+#include <ndn-cxx/security/transform/step-source.hpp>
+#include <ndn-cxx/security/transform/stream-sink.hpp>
+#include <ndn-cxx/util/random.hpp>
+#include <ndn-cxx/encoding/buffer-stream.hpp>
+#include <ndn-cxx/security/transform/hmac-filter.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+const size_t HASH_SIZE = 32;
+
+_LOG_INIT(crypto-support);
+
+ECDHState::ECDHState()
+{
+ OpenSSL_add_all_algorithms();
+ context = std::make_unique<ECDH_CTX>();
+ context->EC_NID = NID_X9_62_prime256v1;
+
+ // Create the context for parameter generation
+ if (nullptr == (context->ctx_params = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr))) {
+ handleErrors("Could not create context contexts.");
+ return;
+ }
+
+ // Initialise the parameter generation
+ if (EVP_PKEY_paramgen_init(context->ctx_params) != 1) {
+ handleErrors("Could not initialize parameter generation.");
+ return;
+ }
+
+ // We're going to use the ANSI X9.62 Prime 256v1 curve
+ if (1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(context->ctx_params, context->EC_NID)) {
+ handleErrors("Likely unknown elliptical curve ID specified.");
+ return;
+ }
+
+ // Create the parameter object params
+ if (!EVP_PKEY_paramgen(context->ctx_params, &context->params)) {
+ // the generated key is written to context->params
+ handleErrors("Could not create parameter object parameters.");
+ return;
+ }
+
+ // Create the context for the key generation
+ if (nullptr == (context->ctx_keygen = EVP_PKEY_CTX_new(context->params, nullptr))) {
+ //The EVP_PKEY_CTX_new() function allocates public key algorithm context using
+ //the algorithm specified in pkey and ENGINE e (in this case nullptr).
+ handleErrors("Could not create the context for the key generation");
+ return;
+ }
+
+ // initializes a public key algorithm context
+ if (1 != EVP_PKEY_keygen_init(context->ctx_keygen)){
+ handleErrors("Could not init context for key generation.");
+ return;
+ }
+ if (1 != EVP_PKEY_keygen(context->ctx_keygen, &context->privkey)) {
+ //performs a key generation operation, the generated key is written to context->privkey.
+ handleErrors("Could not generate DHE keys in final step");
+ return;
+ }
+}
+
+ECDHState::~ECDHState()
+{
+ // Contexts
+ if(context->ctx_params != nullptr){
+ EVP_PKEY_CTX_free(context->ctx_params);
+ }
+ if(context->ctx_keygen != nullptr){
+ EVP_PKEY_CTX_free(context->ctx_keygen);
+ }
+
+ // Keys
+ if(context->privkey != nullptr){
+ EVP_PKEY_free(context->privkey);
+ }
+ if(context->peerkey != nullptr){
+ EVP_PKEY_free(context->peerkey);
+ }
+ if(context->params != nullptr){
+ EVP_PKEY_free(context->params);
+ }
+}
+
+uint8_t*
+ECDHState::getRawSelfPubKey()
+{
+ auto privECKey = EVP_PKEY_get1_EC_KEY(context->privkey);
+
+ if (privECKey == nullptr) {
+ handleErrors("Could not get referenced key when calling EVP_PKEY_get1_EC_KEY().");
+ return nullptr;
+ }
+
+ auto ecPoint = EC_KEY_get0_public_key(privECKey);
+ const EC_GROUP* group = EC_KEY_get0_group(privECKey);
+ context->publicKeyLen = EC_POINT_point2oct(group, ecPoint, POINT_CONVERSION_COMPRESSED,
+ context->publicKey, 256, nullptr);
+ EC_KEY_free(privECKey);
+ if (context->publicKeyLen == 0) {
+ handleErrors("Could not convert EC_POINTS to octet string when calling EC_POINT_point2oct.");
+ return nullptr;
+ }
+
+ return context->publicKey;
+}
+
+std::string
+ECDHState::getBase64PubKey()
+{
+ if (context->publicKeyLen == 0) {
+ this->getRawSelfPubKey();
+ }
+ std::stringstream os;
+ security::transform::bufferSource(context->publicKey, context->publicKeyLen)
+ >> security::transform::base64Encode() >> security::transform::streamSink(os);
+ return os.str();
+}
+
+uint8_t*
+ECDHState::deriveSecret(const uint8_t* peerkey, int peerKeySize)
+{
+ auto privECKey = EVP_PKEY_get1_EC_KEY(context->privkey);
+
+ if (privECKey == nullptr) {
+ handleErrors("Could not get referenced key when calling EVP_PKEY_get1_EC_KEY().");
+ return nullptr;
+ }
+
+ auto group = EC_KEY_get0_group(privECKey);
+ auto peerPoint = EC_POINT_new(group);
+ EC_POINT_oct2point(group, peerPoint, peerkey, peerKeySize, nullptr);
+
+ if (0 == (context->sharedSecretLen = ECDH_compute_key(context->sharedSecret, 256,
+ peerPoint, privECKey, nullptr))) {
+ EC_POINT_free(peerPoint);
+ EC_KEY_free(privECKey);
+ handleErrors("Cannot generate ECDH secret with ECDH_compute_key");
+ }
+ EC_POINT_free(peerPoint);
+ EC_KEY_free(privECKey);
+ return context->sharedSecret;
+}
+
+uint8_t*
+ECDHState::deriveSecret(const std::string& peerKeyStr)
+{
+ namespace t = ndn::security::transform;
+ OBufferStream os;
+ security::transform::bufferSource(peerKeyStr)
+ >> security::transform::base64Decode()
+ >> security::transform::streamSink(os);
+ ConstBufferPtr result = os.buf();
+ return this->deriveSecret(result->data(), result->size());
+}
+
+int ndn_compute_hmac_sha256 (const uint8_t *data, const unsigned data_length,
+ const uint8_t *key, const unsigned key_length,
+ uint8_t *prk) {
+ OBufferStream os;
+
+ security::transform::bufferSource(data, data_length) >>
+ security::transform::hmacFilter(
+ DigestAlgorithm::SHA256, key, key_length) >>
+ security::transform::streamSink(os);
+
+ auto result = os.buf();
+ memcpy(prk, result->data(), HASH_SIZE);
+ return 0;
+}
+
+//removed dependency of OpenSSL@1.1
+int
+hkdf(const uint8_t* secret, int secretLen, const uint8_t* salt,
+ int saltLen, uint8_t* okm, int okm_len,
+ const uint8_t* info, int info_len)
+{
+ // hkdf generate prk
+ uint8_t prk[HASH_SIZE];
+ ndn_compute_hmac_sha256(salt, saltLen, secret, secretLen, prk);
+
+ // hkdf expand
+ uint8_t prev[HASH_SIZE] = {0};
+ int done_len = 0, dig_len = HASH_SIZE, n = okm_len / dig_len;
+ if (okm_len % dig_len) n++;
+ if (n > 255 || okm == nullptr) return 0;
+ for (int i = 1; i <= n; i++) {
+ size_t copy_len;
+ const uint8_t ctr = i;
+ OBufferStream os;
+ security::transform::StepSource source;
+
+ source >> security::transform::hmacFilter(DigestAlgorithm::SHA256, prk, dig_len)
+ >> security::transform::streamSink(os);
+
+ if (i > 1) {
+ source.write(prev, dig_len);
+ }
+
+ source.write(info, info_len);
+ source.write(&ctr, 1);
+ source.end();
+
+ auto result = os.buf();
+ memcpy(prev, result->data(), dig_len);
+
+ copy_len = (done_len + dig_len > okm_len) ?
+ okm_len - done_len :
+ dig_len;
+
+ memcpy(okm + done_len, prev, copy_len);
+ done_len += copy_len;
+ }
+ return done_len;
+}
+
+void
+handleErrors(const std::string& errorInfo)
+{
+ _LOG_DEBUG("Error in CRYPTO SUPPORT " << errorInfo);
+ BOOST_THROW_EXCEPTION(CryptoError("Error in CRYPTO SUPPORT: " + errorInfo));
+}
+
+} // namespace ndncert
+} // namespace ndn
diff --git a/src/crypto-support/crypto-helper.hpp b/src/crypto-support/crypto-helper.hpp
new file mode 100644
index 0000000..7bf6572
--- /dev/null
+++ b/src/crypto-support/crypto-helper.hpp
@@ -0,0 +1,90 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2019, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_CRYPTO_SUPPORT_CRYPTO_HELPER_HPP
+#define NDNCERT_CRYPTO_SUPPORT_CRYPTO_HELPER_HPP
+
+#include "certificate-request.hpp"
+#include <openssl/evp.h>
+#include <openssl/ec.h>
+
+static const int INFO_LEN = 10;
+static const uint8_t INFO[] = {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9};
+
+namespace ndn {
+namespace ndncert {
+
+struct ECDH_CTX{
+ int EC_NID;
+ EVP_PKEY_CTX *ctx_params;
+ EVP_PKEY_CTX *ctx_keygen;
+ EVP_PKEY *privkey;
+ EVP_PKEY *peerkey;
+ EVP_PKEY *params;
+ uint8_t publicKey[256];
+ int publicKeyLen;
+ uint8_t sharedSecret[256];
+ int sharedSecretLen;
+};
+
+class ECDHState
+{
+public:
+ ECDHState();
+ ~ECDHState();
+
+ std::string
+ getBase64PubKey();
+
+ uint8_t*
+ deriveSecret(const std::string& peerKeyStr);
+ //unique_ptr<ECDH_CTX_T> context;
+ unique_ptr<ECDH_CTX> context;
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+ uint8_t*
+ deriveSecret(const uint8_t* peerkey, int peerKeySize);
+
+ uint8_t*
+ getRawSelfPubKey();
+};
+
+int
+hkdf(const uint8_t* secret, int secretLen, const uint8_t* salt,
+ int saltLen, uint8_t* okm, int okm_len,
+ const uint8_t* info=INFO, int info_len=INFO_LEN);
+
+int ndn_compute_hmac_sha256 (const uint8_t *data, const unsigned data_length,
+ const uint8_t *key, const unsigned key_length,
+ uint8_t *prk);
+
+void
+handleErrors(const std::string& errorInfo);
+
+class CryptoError : public std::runtime_error
+{
+public:
+ using std::runtime_error::runtime_error;
+};
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_CRYPTO_SUPPORT_CRYPTO_HELPER_HPP
diff --git a/src/crypto-support/enc-tlv.cpp b/src/crypto-support/enc-tlv.cpp
new file mode 100644
index 0000000..8260957
--- /dev/null
+++ b/src/crypto-support/enc-tlv.cpp
@@ -0,0 +1,78 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2019, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#include "enc-tlv.hpp"
+#include "crypto-helper.hpp"
+#include <ndn-cxx/util/random.hpp>
+#include <ndn-cxx/security/transform/stream-sink.hpp>
+#include <ndn-cxx/encoding/buffer-stream.hpp>
+#include <ndn-cxx/security/transform/buffer-source.hpp>
+#include <ndn-cxx/security/transform/block-cipher.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+const size_t DEFAULT_IV_SIZE = 16;
+
+Block
+genEncBlock(uint32_t tlv_type, const uint8_t* key, size_t keyLen, const uint8_t* payload, size_t payloadSize)
+{
+ Buffer iv;
+ iv.resize(DEFAULT_IV_SIZE);
+ random::generateSecureBytes(iv.data(), iv.size());
+
+ OBufferStream os;
+ security::transform::bufferSource(payload, payloadSize)
+ >> security::transform::blockCipher(BlockCipherAlgorithm::AES_CBC,
+ CipherOperator::ENCRYPT,
+ key, keyLen, iv.data(), iv.size())
+ >> security::transform::streamSink(os);
+ auto encryptedPayload = *os.buf();
+
+ // create the content block
+ auto content = makeEmptyBlock(tlv_type);
+ content.push_back(makeBinaryBlock(ENCRYPTED_PAYLOAD, encryptedPayload.data(), encryptedPayload.size()));
+ content.push_back(makeBinaryBlock(INITIAL_VECTOR, iv.data(), iv.size()));
+ content.encode();
+ return content;
+}
+
+Buffer
+parseEncBlock(const uint8_t* key, size_t keyLen, const Block& block)
+{
+ block.parse();
+ Buffer iv(block.get(INITIAL_VECTOR).value(),
+ block.get(INITIAL_VECTOR).value_size());
+ Buffer encryptedPayload(block.get(ENCRYPTED_PAYLOAD).value(),
+ block.get(ENCRYPTED_PAYLOAD).value_size());
+
+ OBufferStream os;
+ security::transform::bufferSource(encryptedPayload.data(), encryptedPayload.size())
+ >> security::transform::blockCipher(BlockCipherAlgorithm::AES_CBC,
+ CipherOperator::DECRYPT,
+ key, keyLen, iv.data(), iv.size())
+ >> security::transform::streamSink(os);
+
+ auto payload = *os.buf();
+ return payload;
+}
+
+} // namespace ndncert
+} // namespace ndn
diff --git a/src/crypto-support/enc-tlv.hpp b/src/crypto-support/enc-tlv.hpp
new file mode 100644
index 0000000..07f17a5
--- /dev/null
+++ b/src/crypto-support/enc-tlv.hpp
@@ -0,0 +1,44 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2019, Regents of the University of California.
+ *
+ * This file is part of ndncert, a certificate management system based on NDN.
+ *
+ * ndncert is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation, either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+ * PARTICULAR PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received copies of the GNU General Public License along with
+ * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * See AUTHORS.md for complete list of ndncert authors and contributors.
+ */
+
+#ifndef NDNCERT_CRYPTO_SUPPORT_ENC_TLV_HPP
+#define NDNCERT_CRYPTO_SUPPORT_ENC_TLV_HPP
+
+#include <ndn-cxx/encoding/block-helpers.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+enum {
+ ENCRYPTED_PAYLOAD = 630,
+ INITIAL_VECTOR = 632,
+};
+
+Block
+genEncBlock(uint32_t tlv_type, const uint8_t* key, size_t keyLen, const uint8_t* payload, size_t payloadSize);
+
+Buffer
+parseEncBlock(const uint8_t* key, size_t keyLen, const Block& block);
+
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_CRYPTO_SUPPORT_ENC_TLV_HPP
diff --git a/src/json-helper.cpp b/src/json-helper.cpp
deleted file mode 100644
index 81fa829..0000000
--- a/src/json-helper.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2017, Regents of the University of California.
- *
- * This file is part of ndncert, a certificate management system based on NDN.
- *
- * ndncert is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received copies of the GNU General Public License along with
- * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndncert authors and contributors.
- */
-
-#include "json-helper.hpp"
-#include <boost/lexical_cast.hpp>
-
-namespace ndn {
-namespace ndncert {
-
-const JsonSection
-genResponseProbeJson(const Name& identifier, const Name& caInformation)
-{
- JsonSection root;
-
- root.put(JSON_IDNENTIFIER, identifier.toUri());
- root.put(JSON_CA_INFO, caInformation.toUri());
-
- return root;
-}
-
-const JsonSection
-genResponseNewJson(const std::string& requestId, const std::string& status,
- const std::list<std::string>& challenges)
-{
- JsonSection root;
- JsonSection challengesSection;
- root.put(JSON_REQUEST_ID, requestId);
- root.put(JSON_STATUS, status);
-
- for (const auto& entry : challenges) {
- JsonSection challenge;
- challenge.put(JSON_CHALLENGE_TYPE, entry);
- challengesSection.push_back(std::make_pair("", challenge));
- }
- root.add_child(JSON_CHALLENGES, challengesSection);
-
- return root;
-}
-
-const JsonSection
-genResponseChallengeJson(const std::string& requestId, const std::string& challengeType,
- const std::string& status, const Name& name)
-{
- JsonSection root;
- root.put(JSON_REQUEST_ID, requestId);
- root.put(JSON_CHALLENGE_TYPE, challengeType);
- root.put(JSON_STATUS, status);
- if (name.toUri() != "") {
- root.put(JSON_CERTIFICATE, name.toUri());
- }
- return root;
-}
-
-const JsonSection
-genFailureJson(const std::string& requestId, const std::string& challengeType,
- const std::string& status, const std::string& failureInfo)
-{
- JsonSection root;
- root.put(JSON_REQUEST_ID, requestId);
- root.put(JSON_CHALLENGE_TYPE, challengeType);
- root.put(JSON_STATUS, status);
- root.put(JSON_FAILURE_INFO, failureInfo);
- return root;
-}
-
-} // namespace ndncert
-} // namespace ndn
diff --git a/src/json-helper.hpp b/src/json-helper.hpp
deleted file mode 100644
index 4540596..0000000
--- a/src/json-helper.hpp
+++ /dev/null
@@ -1,116 +0,0 @@
-/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
-/**
- * Copyright (c) 2017, Regents of the University of California.
- *
- * This file is part of ndncert, a certificate management system based on NDN.
- *
- * ndncert is free software: you can redistribute it and/or modify it under the terms
- * of the GNU General Public License as published by the Free Software Foundation, either
- * version 3 of the License, or (at your option) any later version.
- *
- * ndncert is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received copies of the GNU General Public License along with
- * ndncert, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
- *
- * See AUTHORS.md for complete list of ndncert authors and contributors.
- */
-
-#ifndef NDNCERT_JSON_HELPER_HPP
-#define NDNCERT_JSON_HELPER_HPP
-
-#include "certificate-request.hpp"
-
-namespace ndn {
-namespace ndncert {
-
-const std::string JSON_IDNENTIFIER = "identifier";
-const std::string JSON_CA_INFO = "ca-info";
-const std::string JSON_STATUS = "status";
-const std::string JSON_REQUEST_ID = "request-id";
-const std::string JSON_CHALLENGES = "challenges";
-const std::string JSON_CHALLENGE_TYPE = "challenge-type";
-const std::string JSON_FAILURE_INFO = "failure-info";
-const std::string JSON_CERTIFICATE = "certificate";
-
-/**
- * @brief Generate JSON file to response PROBE insterest
- *
- * Target JSON format:
- * {
- * "identifier": "@p identifier",
- * "ca-info": "@p caInformation"
- * }
- */
-const JsonSection
-genResponseProbeJson(const Name& identifier, const Name& caInformation);
-
-/**
- * @brief Generate JSON file to response NEW interest
- *
- * Target JSON format:
- * {
- * "request-id": "@p requestId",
- * "status": "@p status",
- * "challenges": [
- * {
- * "challenge-type": ""
- * },
- * {
- * "challenge-type": ""
- * },
- * ...
- * ]
- * }
- */
-const JsonSection
-genResponseNewJson(const std::string& requestId, const std::string& status,
- const std::list<std::string>& challenges);
-
-/**
- * @brief Generate JSON file to response _SELECT, _VALIDATE, and _STATUS interest
- *
- * if certificate name is not present:
- *
- * Target JSON format:
- * {
- * "request-id": "@p requestId",
- * "challenge-type": "@p challengeType",
- * "status": "@p status"
- * }
- *
- * if certificate name is present:
- *
- * Target JSON format:
- * {
- * "request-id": "@p requestId",
- * "challenge-type": "@p challengeType",
- * "status": "@p status",
- * "certificate":"@p name"
- * }
- */
-const JsonSection
-genResponseChallengeJson(const std::string& requestId, const std::string& challengeType,
- const std::string& status, const Name& name = Name());
-
-/**
- * @brief Generate JSON file when there is an Error
- *
- * Target JSON format:
- * {
- * "request-id": "@p requestId",
- * "challenge-type": "@p challengeType",
- * "status": "failure",
- * "failure-info": "@p errorInfo",
- * }
- */
-const JsonSection
-genFailureJson(const std::string& requestId, const std::string& challengeType,
- const std::string& status, const std::string& failureInfo);
-
-} // namespace ndncert
-} // namespace ndn
-
-#endif // NDNCERT_JSON_HELPER_HPP
diff --git a/src/ndncert-common.hpp b/src/ndncert-common.hpp
index b7e4a60..bf314cd 100644
--- a/src/ndncert-common.hpp
+++ b/src/ndncert-common.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017, Regents of the University of California.
+ * Copyright (c) 2017-2019, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -70,19 +70,15 @@
namespace ndncert {
using std::size_t;
-
using boost::noncopyable;
-
using std::shared_ptr;
using std::unique_ptr;
using std::weak_ptr;
using std::make_shared;
using ndn::make_unique;
using std::enable_shared_from_this;
-
using std::function;
using std::bind;
-
using ndn::Interest;
using ndn::Data;
using ndn::Name;
@@ -91,6 +87,44 @@
using ndn::time::system_clock;
using ndn::time::toUnixTimestamp;
+// JSON format for Certificate Issuer (CA)
+const std::string JSON_CA_NAME = "name";
+const std::string JSON_CA_CONFIG = "ca-config";
+const std::string JSON_CA_ECDH = "ecdh-pub";
+const std::string JSON_CA_SALT = "salt";
+const std::string JSON_CA_EQUEST_ID = "request-id";
+const std::string JSON_CA_STATUS = "status";
+const std::string JSON_CA_CHALLENGES = "challenges";
+const std::string JSON_CA_CHALLENGE_ID = "challenge-id";
+const std::string JSON_CA_CERT_ID = "certificate-id";
+
+// JSON format for Challenge Module
+const std::string JSON_CHALLENGE_STATUS = "challenge-status";
+const std::string JSON_CHALLENGE_REMAINING_TRIES = "remaining-tries";
+const std::string JSON_CHALLENGE_REMAINING_TIME = "remaining-time";
+
+// JSON format for Certificate Requester
+const std::string JSON_CLIENT_PROBE_INFO = "probe-info";
+const std::string JSON_CLIENT_ECDH = "ecdh-pub";
+const std::string JSON_CLIENT_CERT_REQ = "cert-request";
+const std::string JSON_CLIENT_SELECTED_CHALLENGE = "selected-challenge";
+
+// NDNCERT Status Enum
+enum {
+ STATUS_BEFORE_CHALLENGE = 0,
+ STATUS_CHALLENGE = 1,
+ STATUS_PENDING = 2,
+ STATUS_SUCCESS = 3,
+ STATUS_FAILURE = 4,
+ STATUS_NOT_STARTED = 5
+};
+
+// Pre-defined challenge status
+const std::string CHALLENGE_STATUS_SUCCESS = "success";
+const std::string CHALLENGE_STATUS_FAILURE_TIMEOUT = "failure-timeout";
+const std::string CHALLENGE_STATUS_FAILURE_MAXRETRY = "failure-max-retry";
+const std::string CHALLENGE_STATUS_UNKNOWN_CHALLENGE = "unknown-challenge";
+
} // namespace ndncert
} // namespace ndn