TLV encoding to replace JSON format message
diff --git a/src/ca-config.hpp b/src/ca-config.hpp
index 5bf4f44..4ff3fe1 100644
--- a/src/ca-config.hpp
+++ b/src/ca-config.hpp
@@ -42,7 +42,7 @@
* @p vector, input, a list of parameter key-value pair used for name assignment.
* @return a vector containing the possible namespaces derived from the parameters.
*/
-using ProbeHandler = function<std::string /*identity name*/ (const JsonSection& json /*requester input*/)>;
+using ProbeHandler = function<std::string /*identity name*/ (const Block& tlv /*requester input*/)>;
using NameAssignmentFunc = function<std::vector<std::string>(const std::vector<std::tuple<std::string, std::string>>)>;
/**
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index be44e11..275e1f8 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -22,7 +22,10 @@
#include "challenge-module.hpp"
#include "logging.hpp"
#include "crypto-support/enc-tlv.hpp"
-#include "tlv.hpp"
+#include "protocol-detail/info.hpp"
+#include "protocol-detail/probe.hpp"
+#include "protocol-detail/new.hpp"
+#include "protocol-detail/challenge.hpp"
#include <ndn-cxx/util/io.hpp>
#include <ndn-cxx/security/verification-helpers.hpp>
#include <ndn-cxx/security/signing-helpers.hpp>
@@ -120,7 +123,11 @@
CaModule::onInfo(const Interest& request)
{
_LOG_TRACE("Received INFO request");
- Block contentTLV = genInfoResponseTLV();
+
+ const auto& pib = m_keyChain.getPib();
+ const auto& identity = pib.getIdentity(m_config.m_caName);
+ const auto& cert = identity.getDefaultKey().getDefaultCertificate();
+ Block contentTLV = INFO::encodeContentFromCAConfig(m_config, cert);
Data result;
result.setName(request.getName());
@@ -138,19 +145,19 @@
{
// PROBE Naming Convention: /<CA-Prefix>/CA/PROBE/[ParametersSha256DigestComponent]
_LOG_TRACE("Received PROBE request");
- JsonSection contentJson;
// process PROBE requests: find an available name
std::string availableId;
- const auto& parameterJson = jsonFromBlock(request.getApplicationParameters());
- if (parameterJson.empty()) {
- _LOG_ERROR("Empty JSON obtained from the Interest parameter.");
+ const auto& parameterTLV = request.getApplicationParameters();
+ if (!parameterTLV.hasValue()) {
+ _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
return;
}
//std::string probeInfoStr = parameterJson.get(JSON_CLIENT_PROBE_INFO, "");
+ // TODO: m_probeHandler is never set
if (m_config.m_probeHandler) {
try {
- availableId = m_config.m_probeHandler(parameterJson);
+ availableId = m_config.m_probeHandler(parameterTLV);
}
catch (const std::exception& e) {
_LOG_TRACE("Cannot find PROBE input from PROBE parameters: " << e.what());
@@ -164,11 +171,11 @@
Name newIdentityName = m_config.m_caName;
newIdentityName.append(availableId);
_LOG_TRACE("Handle PROBE: generate an identity " << newIdentityName);
- contentJson = genProbeResponseJson(newIdentityName.toUri(), m_config.m_probe, parameterJson);
+ Block contentTLV = PROBE::encodeDataContent(newIdentityName.toUri(), m_config.m_probe, parameterTLV);
Data result;
result.setName(request.getName());
- result.setContent(dataContentFromJson(contentJson));
+ result.setContent(contentTLV);
result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
m_face.put(result);
@@ -180,14 +187,16 @@
{
// NEW Naming Convention: /<CA-prefix>/CA/NEW/[SignedInterestParameters_Digest]
// get ECDH pub key and cert request
- const auto& parameterJson = jsonFromBlock(request.getApplicationParameters());
- if (parameterJson.empty()) {
- _LOG_ERROR("Empty JSON obtained from the Interest parameter.");
+ const auto& parameterTLV = request.getApplicationParameters();
+ if (!parameterTLV.hasValue()) {
+ _LOG_ERROR("Empty TLV obtained from the Interest parameter.");
return;
}
- std::string peerKeyBase64 = parameterJson.get(JSON_CLIENT_ECDH, "");
+
+ std::string peerKeyBase64 = readString(parameterTLV.get(tlv_ecdh_pub));
+
if (peerKeyBase64 == "") {
- _LOG_ERROR("Empty JSON_CLIENT_ECDH obtained from the Interest parameter.");
+ _LOG_ERROR("Empty ECDH PUB obtained from the Interest parameter.");
return;
}
@@ -207,11 +216,10 @@
(uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
// parse certificate request
- std::string certRequestStr = parameterJson.get(JSON_CLIENT_CERT_REQ, "");
+ Block cert_req = parameterTLV.get(tlv_cert_request);
shared_ptr<security::v2::Certificate> clientCert = nullptr;
try {
- std::stringstream ss(certRequestStr);
- clientCert = io::load<security::v2::Certificate>(ss);
+ clientCert->wireDecode(cert_req);
}
catch (const std::exception& e) {
_LOG_ERROR("Unrecognized certificate request: " << e.what());
@@ -230,34 +238,6 @@
return;
}
- // parse probe token if any
- std::string probeTokenStr = parameterJson.get("probe-token", "");
- shared_ptr<Data> probeToken = nullptr;
- if (probeTokenStr != "") {
- try {
- std::stringstream ss(probeTokenStr);
- probeToken = io::load<Data>(ss);
- }
- catch (const std::exception& e) {
- _LOG_ERROR("Unrecognized probe token: " << e.what());
- return;
- }
- }
- if (probeToken == nullptr && m_config.m_probe != "") {
- // the CA requires PROBE before NEW
- _LOG_ERROR("CA requires PROBE but no PROBE token is found in NEW Interest.");
- return;
- }
- else if (probeToken != nullptr) {
- // check whether the carried probe token is a PROBE Data packet
- Name prefix = m_config.m_caName;
- prefix.append("CA").append("PROBE");
- if (!prefix.isPrefixOf(probeToken->getName())) {
- _LOG_ERROR("Carried PROBE token is not a valid PROBE Data packet.");
- return;
- }
- }
-
// verify the self-signed certificate, the request, and the token
if (!m_config.m_caName.isPrefixOf(clientCert->getName()) // under ca prefix
|| !security::v2::Certificate::isValidName(clientCert->getName()) // is valid cert name
@@ -273,22 +253,11 @@
_LOG_ERROR("Interest with bad signature.");
return;
}
- if (probeToken != nullptr) {
- const auto& pib = m_keyChain.getPib();
- const auto& key = pib.getIdentity(m_config.m_caName).getDefaultKey();
- const auto& caCert = key.getDefaultCertificate();
- if (!security::verifySignature(*probeToken, caCert)) {
- _LOG_ERROR("PROBE Token with bad signature.");
- return;
- }
- }
// create new request instance
std::string requestId = std::to_string(random::generateWord64());
CertificateRequest certRequest(m_config.m_caName, requestId, STATUS_BEFORE_CHALLENGE, *clientCert);
- if (probeToken != nullptr) {
- certRequest.setProbeToken(probeToken);
- }
+
try {
m_storage->addRequest(certRequest);
}
@@ -300,10 +269,10 @@
Data result;
result.setName(request.getName());
result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
- result.setContent(dataContentFromJson(genNewResponseJson(myEcdhPubKeyBase64,
- std::to_string(saltInt),
- certRequest,
- m_config.m_supportedChallenges)));
+ result.setContent(NEW::encodeDataContent(myEcdhPubKeyBase64,
+ std::to_string(saltInt),
+ certRequest,
+ m_config.m_supportedChallenges));
m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
m_face.put(result);
@@ -328,48 +297,45 @@
return;
}
// decrypt the parameters
- Buffer paramJsonPayload;
+ Buffer paramTLVPayload;
try {
- paramJsonPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), m_aesKey,
+ paramTLVPayload = decodeBlockWithAesGcm128(request.getApplicationParameters(), m_aesKey,
(uint8_t*)"test", strlen("test"));
}
catch (const std::exception& e) {
_LOG_ERROR("Cannot successfully decrypt the Interest parameters: " << e.what());
return;
}
- if (paramJsonPayload.size() == 0) {
+ if (paramTLVPayload.size() == 0) {
_LOG_ERROR("Got an empty buffer from content decryption.");
return;
}
- std::string paramJsonStr((const char*)paramJsonPayload.data(), paramJsonPayload.size());
- std::istringstream ss(paramJsonStr);
- JsonSection paramJson;
- try {
- boost::property_tree::json_parser::read_json(ss, paramJson);
- }
- catch (const std::exception& e) {
- _LOG_ERROR("Cannot read JSON from decrypted content: " << e.what());
- return;
- }
+
+ // TODO: any simpler method?
+ bool isSucess;
+ Block paramTLV;
+ std::tie<bool, Block>(isSucess, paramTLV) = Block::fromBuffer(paramTLVPayload.data(), paramTLVPayload.size());
// load the corresponding challenge module
- std::string challengeType = paramJson.get(JSON_CLIENT_SELECTED_CHALLENGE, "");
+ std::string challengeType = readString(paramTLV.get(tlv_selected_challenge));
auto challenge = ChallengeModule::createChallengeModule(challengeType);
- JsonSection contentJson;
+
+ Block contentTLV;
+
if (challenge == nullptr) {
_LOG_TRACE("Unrecognized challenge type " << challengeType);
certRequest.m_status = STATUS_FAILURE;
certRequest.m_challengeStatus = CHALLENGE_STATUS_UNKNOWN_CHALLENGE;
- contentJson = genChallengeResponseJson(certRequest);
+ contentTLV = CHALLENGE::encodeDataPayload(certRequest);
}
else {
_LOG_TRACE("CHALLENGE module to be load: " << challengeType);
// let challenge module handle the request
- challenge->handleChallengeRequest(paramJson, certRequest);
+ challenge->handleChallengeRequest(paramTLV, certRequest);
if (certRequest.m_status == STATUS_FAILURE) {
// if challenge failed
m_storage->deleteRequest(certRequest.m_requestId);
- contentJson = genChallengeResponseJson(certRequest);
+ contentTLV = CHALLENGE::encodeDataPayload(certRequest);
_LOG_TRACE("Challenge failed");
}
else if (certRequest.m_status == STATUS_PENDING) {
@@ -389,9 +355,12 @@
if (m_config.m_statusUpdateCallback) {
m_config.m_statusUpdateCallback(certRequest);
}
- contentJson = genChallengeResponseJson(certRequest);
- contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
- contentJson.add(JSON_CHALLENGE_ISSUED_CERT_NAME, issuedCert.getName().toUri());
+
+ contentTLV = CHALLENGE::encodeDataPayload(certRequest);
+ contentTLV.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
+ contentTLV.parse();
+
+ //contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
_LOG_TRACE("Challenge succeeded. Certificate has been issued");
}
else {
@@ -402,7 +371,7 @@
_LOG_TRACE("Cannot update request instance: " << e.what());
return;
}
- contentJson = genChallengeResponseJson(certRequest);
+ contentTLV = CHALLENGE::encodeDataPayload(certRequest);
_LOG_TRACE("No failure no success. Challenge moves on");
}
}
@@ -412,11 +381,9 @@
result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
// encrypt the content
- std::stringstream ss2;
- boost::property_tree::write_json(ss2, contentJson);
- auto payload = ss2.str();
- auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, m_aesKey, (const uint8_t*)payload.c_str(),
- payload.size(), (uint8_t*)"test", strlen("test"));
+ auto payload = contentTLV.getBuffer();
+ auto contentBlock = encodeBlockWithAesGcm128(tlv::Content, m_aesKey, payload->data(),
+ payload->size(), (uint8_t*)"test", strlen("test"));
result.setContent(contentBlock);
m_keyChain.sign(result, signingByIdentity(m_config.m_caName));
m_face.put(result);
@@ -552,46 +519,6 @@
return root;
}
-Block
-CaModule::genInfoResponseTLV()
-{
- Block response;
- // ca-prefix
- Name caName = m_config.m_caName;
- // response = makeStringBlock(CAPrefix, caName.toUri());
- response = makeNestedBlock(CAPrefix, caName);
-
- // ca-info
- const auto& pib = m_keyChain.getPib();
- const auto& identity = pib.getIdentity(m_config.m_caName);
- const 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;
- }
-
- response.push_back(makeStringBlock(CAInfo, caInfo));
-
-
- // parameter-key (Not implemented yet)
- for() {
- response.push_back(makeStringBlock(ParameterKey, ""));
- }
-
- // TODO: need to convert from days to seconds
- response.push_back(makeNonNegativeIntegerBlock(MaxValidityPeriod, m_validityPeriod));
-
- // certificate
- response.push_back(makeNestedBlock(CACertificate, cert));
- response.parse();
-
- return response;
-}
-
-
JsonSection
CaModule::genNewResponseJson(const std::string& ecdhKey, const std::string& salt,
const CertificateRequest& request,
diff --git a/src/challenge-module.hpp b/src/challenge-module.hpp
index 80670f4..4cc5fa9 100644
--- a/src/challenge-module.hpp
+++ b/src/challenge-module.hpp
@@ -66,7 +66,7 @@
// For CA
virtual void
- handleChallengeRequest(const JsonSection& params, CertificateRequest& request) = 0;
+ handleChallengeRequest(const Block& params, CertificateRequest& request) = 0;
// For Client
virtual JsonSection
@@ -75,6 +75,9 @@
virtual JsonSection
genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) = 0;
+ virtual Block
+ genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params) = 0;
+
// helpers
static std::string
generateSecretCode();
diff --git a/src/challenge-module/challenge-credential.cpp b/src/challenge-module/challenge-credential.cpp
index 69a6bbe..a4ca557 100644
--- a/src/challenge-module/challenge-credential.cpp
+++ b/src/challenge-module/challenge-credential.cpp
@@ -78,13 +78,14 @@
// For CA
void
-ChallengeCredential::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
+ChallengeCredential::handleChallengeRequest(const Block& params, CertificateRequest& request)
{
if (m_trustAnchors.empty()) {
parseConfigFile();
}
// load credential parameter
- std::istringstream ss1(params.get(JSON_CREDENTIAL_CERT, ""));
+ // TODO: instead of string, should pass certificate byte value directly
+ std::istringstream ss1(readString(params.elements().at(1)));
auto cert = io::load<security::v2::Certificate>(ss1);
if (cert == nullptr) {
_LOG_ERROR("Cannot load credential parameter: cert");
@@ -95,8 +96,9 @@
}
ss1.str("");
ss1.clear();
+
// load self-signed data
- std::istringstream ss2(params.get(JSON_CREDENTIAL_SELF, ""));
+ std::istringstream ss2(readString(params.elements().at(3)));
auto self = io::load<Data>(ss2);
if (self == nullptr) {
_LOG_TRACE("Cannot load credential parameter: self-signed cert");
@@ -158,5 +160,24 @@
return result;
}
+Block
+ChallengeCredential::genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params)
+{
+ Block request = makeEmptyBlock(tlv_encrypted_payload);
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_CERT));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_CERT,"")));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_CREDENTIAL_SELF));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CREDENTIAL_SELF,"")));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
+ request.parse();
+ return request;
+}
+
+
} // namespace ndncert
} // namespace ndn
diff --git a/src/challenge-module/challenge-credential.hpp b/src/challenge-module/challenge-credential.hpp
index 5d4a93c..bf53175 100644
--- a/src/challenge-module/challenge-credential.hpp
+++ b/src/challenge-module/challenge-credential.hpp
@@ -53,7 +53,7 @@
// For CA
void
- handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+ handleChallengeRequest(const Block& params, CertificateRequest& request) override;
// For Client
JsonSection
@@ -62,6 +62,9 @@
JsonSection
genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
+ Block
+ genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params) override;
+
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
void
parseConfigFile();
diff --git a/src/challenge-module/challenge-email.cpp b/src/challenge-module/challenge-email.cpp
index b9ca344..db069c8 100644
--- a/src/challenge-module/challenge-email.cpp
+++ b/src/challenge-module/challenge-email.cpp
@@ -48,12 +48,12 @@
// For CA
void
-ChallengeEmail::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
+ChallengeEmail::handleChallengeRequest(const Block& params, CertificateRequest& request)
{
auto currentTime = time::system_clock::now();
if (request.m_challengeStatus == "") {
// for the first time, init the challenge
- std::string emailAddress = params.get(JSON_EMAIL, "");
+ std::string emailAddress = readString(params.get(tlv_parameter_value));
if (!isValidEmailAddress(emailAddress)) {
request.m_status = STATUS_FAILURE;
request.m_challengeStatus = FAILURE_INVALID_EMAIL;
@@ -91,7 +91,7 @@
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(JSON_CODE, "");
+ std::string givenCode = readString(params.get(tlv_parameter_value));
const auto realCode = request.m_challengeSecrets.get<std::string>(JSON_CODE);
if (currentTime - time::fromIsoString(request.m_challengeTp) >= m_secretLifetime) {
// secret expires
@@ -178,6 +178,32 @@
return result;
}
+Block
+ChallengeEmail::genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params)
+{
+ Block request = makeEmptyBlock(tlv_encrypted_payload);
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_EMAIL));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_EMAIL,"")));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_CODE));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CODE,"")));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_CODE));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_CODE,"")));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
+ request.parse();
+ return request;
+}
+
bool
ChallengeEmail::isValidEmailAddress(const std::string& emailAddress)
{
diff --git a/src/challenge-module/challenge-email.hpp b/src/challenge-module/challenge-email.hpp
index 2f40f1f..4421bd3 100644
--- a/src/challenge-module/challenge-email.hpp
+++ b/src/challenge-module/challenge-email.hpp
@@ -23,6 +23,7 @@
#include "../challenge-module.hpp"
#include <ndn-cxx/util/time.hpp>
+#include <ndn-cxx/encoding/block.hpp>
namespace ndn {
namespace ndncert {
@@ -58,7 +59,7 @@
// For CA
void
- handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+ handleChallengeRequest(const Block& params, CertificateRequest& request) override;
// For Client
JsonSection
@@ -67,6 +68,9 @@
JsonSection
genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
+ Block
+ genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params) override;
+
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
static bool
isValidEmailAddress(const std::string& emailAddress);
diff --git a/src/challenge-module/challenge-pin.cpp b/src/challenge-module/challenge-pin.cpp
index 87f36cc..f31ca77 100644
--- a/src/challenge-module/challenge-pin.cpp
+++ b/src/challenge-module/challenge-pin.cpp
@@ -42,7 +42,7 @@
// For CA
void
-ChallengePin::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
+ChallengePin::handleChallengeRequest(const Block& params, CertificateRequest& request)
{
auto currentTime = time::system_clock::now();
if (request.m_challengeStatus == "") {
@@ -64,7 +64,7 @@
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(JSON_PIN_CODE, "");
+ std::string givenCode = readString(params.get(tlv_parameter_value));
const auto realCode = request.m_challengeSecrets.get<std::string>(JSON_PIN_CODE);
if (currentTime - time::fromIsoString(request.m_challengeTp) >= m_secretLifetime) {
// secret expires
@@ -151,5 +151,29 @@
return result;
}
+Block
+ChallengePin::genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params)
+{
+ Block request = makeEmptyBlock(tlv_encrypted_payload);
+ if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
+ // do nothing
+ request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == NEED_CODE) {
+ request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_PIN_CODE));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_PIN_CODE,"")));
+ }
+ else if (status == STATUS_CHALLENGE && challengeStatus == WRONG_CODE) {
+ request.push_back(makeStringBlock(tlv_selected_challenge, CHALLENGE_TYPE));
+ request.push_back(makeStringBlock(tlv_parameter_key, JSON_PIN_CODE));
+ request.push_back(makeStringBlock(tlv_parameter_value, params.get(JSON_PIN_CODE,"")));
+ }
+ else {
+ _LOG_ERROR("Client's status and challenge status are wrong");
+ }
+ request.parse();
+ return request;
+}
} // namespace ndncert
} // namespace ndn
diff --git a/src/challenge-module/challenge-pin.hpp b/src/challenge-module/challenge-pin.hpp
index 8eef944..7ae1d75 100644
--- a/src/challenge-module/challenge-pin.hpp
+++ b/src/challenge-module/challenge-pin.hpp
@@ -53,7 +53,7 @@
// For CA
void
- handleChallengeRequest(const JsonSection& params, CertificateRequest& request) override;
+ handleChallengeRequest(const Block& params, CertificateRequest& request) override;
// For Client
JsonSection
@@ -62,6 +62,10 @@
JsonSection
genChallengeRequestJson(int status, const std::string& challengeStatus, const JsonSection& params) override;
+ Block
+ genChallengeRequestTLV(int status, const std::string& challengeStatus, const JsonSection& params) override;
+
+
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
// challenge status
static const std::string NEED_CODE;
diff --git a/src/client-config.cpp b/src/client-config.cpp
index 9273760..47115bb 100644
--- a/src/client-config.cpp
+++ b/src/client-config.cpp
@@ -84,21 +84,17 @@
}
ClientCaItem
-ClientConfig::extractCaItem(const Block& contentBlock)
+ClientConfig::extractCaItem(const JsonSection& configSection)
{
ClientCaItem item;
- item.m_caName = Name(readString(contentBlock.get(CAPrefix)));
+ item.m_caName = Name(configSection.get("ca-prefix", ""));
if (item.m_caName.empty()) {
BOOST_THROW_EXCEPTION(Error("Cannot read ca-prefix from the config file"));
}
- item.m_caInfo = readString(contentBlock.get(CAInfo));
- // item.m_probe = configSection.get("probe", "");
-
- security::v2::Certificate anchor = contentBlock.get(CACertificate);
-
- //std::istringstream ss(configSection.get("certificate", ""));
- //auto anchor = io::load<security::v2::Certificate>(ss);
-
+ item.m_caInfo = configSection.get("ca-info", "");
+ item.m_probe = configSection.get("probe", "");
+ std::istringstream ss(configSection.get("certificate", ""));
+ auto anchor = io::load<security::v2::Certificate>(ss);
if (anchor == nullptr) {
BOOST_THROW_EXCEPTION(Error("Cannot load the certificate from config file"));
}
@@ -106,6 +102,28 @@
return item;
}
+ClientCaItem
+ClientConfig::extractCaItem(const Block& contentBlock)
+{
+ ClientCaItem item;
+ item.m_caName = Name(readString(contentBlock.get(tlv_ca_prefix)));
+ if (item.m_caName.empty()) {
+ BOOST_THROW_EXCEPTION(Error("Cannot read ca-prefix from the config file"));
+ }
+ item.m_caInfo = readString(contentBlock.get(tlv_ca_info));
+ // item.m_probe = configSection.get("probe", "");
+
+ if (!contentBlock.get(tlv_ca_certificate).hasValue()) {
+ BOOST_THROW_EXCEPTION(Error("Cannot load the certificate from config file"));
+ }
+
+ security::v2::Certificate anchor;
+ anchor.wireDecode(contentBlock.get(tlv_ca_certificate));
+ item.m_anchor = anchor;
+
+ return item;
+}
+
void
ClientConfig::removeCaItem(const Name& caName)
{
diff --git a/src/client-config.hpp b/src/client-config.hpp
index 0195c48..876535d 100644
--- a/src/client-config.hpp
+++ b/src/client-config.hpp
@@ -106,6 +106,9 @@
static ClientCaItem
extractCaItem(const JsonSection& configSection);
+ static ClientCaItem
+ extractCaItem(const Block& configSection);
+
public:
std::list<ClientCaItem> m_caItems;
std::string m_localNdncertAnchor;
diff --git a/src/client-module.cpp b/src/client-module.cpp
index 1789632..7049961 100644
--- a/src/client-module.cpp
+++ b/src/client-module.cpp
@@ -22,6 +22,10 @@
#include "logging.hpp"
#include "challenge-module.hpp"
#include "crypto-support/enc-tlv.hpp"
+#include "protocol-detail/info.hpp"
+#include "protocol-detail/probe.hpp"
+#include "protocol-detail/new.hpp"
+#include "protocol-detail/challenge.hpp"
#include <ndn-cxx/util/io.hpp>
#include <ndn-cxx/security/signing-helpers.hpp>
#include <ndn-cxx/security/verification-helpers.hpp>
@@ -59,10 +63,10 @@
}
bool
-ClientModule::verifyProbeInfoResponse(const Block& contentBlock)
+ClientModule::verifyInfoResponse(const Data& reply)
{
// parse the ca item
- auto caItem = ClientConfig::extractCaItem(contentBlock);
+ auto caItem = INFO::decodeClientConfigFromContent(reply.getContent());
// verify the probe Data's sig
if (!security::verifySignature(reply, caItem.m_anchor)) {
@@ -73,12 +77,12 @@
}
void
-ClientModule::addCaFromProbeInfoResponse(const Data& reply)
+ClientModule::addCaFromInfoResponse(const Data& reply)
{
const Block& contentBlock = reply.getContent();
// parse the ca item
- auto caItem = ClientConfig::extractCaItem(contentBlock);
+ auto caItem = INFO::decodeClientConfigFromContent(contentBlock);
// update the local config
bool findItem = false;
@@ -101,8 +105,9 @@
auto interest = make_shared<Interest>(interestName);
interest->setMustBeFresh(true);
interest->setCanBePrefix(false);
- auto paramJson = genProbeRequestJson(ca, probeInfo);
- interest->setApplicationParameters(paramFromJson(paramJson));
+ interest->setApplicationParameters(
+ PROBE::encodeApplicationParametersFromProbeInfo(ca, probeInfo)
+ );
// update local state
m_ca = ca;
@@ -116,12 +121,12 @@
_LOG_ERROR("Cannot verify data signature from " << m_ca.m_caName.toUri());
return;
}
- auto contentJson = getJsonFromData(reply);
+
+ auto contentTLV = reply.getContent();
// read the available name and put it into the state
- auto nameUri = contentJson.get(JSON_CA_NAME, "");
- if (nameUri != "") {
- m_identityName = Name(nameUri);
+ if (contentTLV.get(tlv_probe_response).hasValue()) {
+ m_identityName.wireDecode(contentTLV.get(tlv_probe_response));
}
else {
NDN_LOG_TRACE("The JSON_CA_NAME is empty.");
@@ -194,7 +199,9 @@
auto interest = make_shared<Interest>(interestName);
interest->setMustBeFresh(true);
interest->setCanBePrefix(false);
- interest->setApplicationParameters(paramFromJson(genNewRequestJson(m_ecdh.getBase64PubKey(), certRequest, probeToken)));
+ interest->setApplicationParameters(
+ NEW::encodeApplicationParameters(m_ecdh.getBase64PubKey(), certRequest, probeToken)
+ );
// sign the Interest packet
m_keyChain.sign(*interest, signingByKey(m_key.getName()));
@@ -208,11 +215,11 @@
_LOG_ERROR("Cannot verify data signature from " << m_ca.m_caName.toUri());
return std::list<std::string>();
}
- auto contentJson = getJsonFromData(reply);
+ auto contentTLV = reply.getContent();
// ECDH
- const auto& peerKeyBase64Str = contentJson.get(JSON_CA_ECDH, "");
- const auto& saltStr = contentJson.get(JSON_CA_SALT, "");
+ const auto& peerKeyBase64Str = readString(contentTLV.get(tlv_ecdh_pub));
+ const auto& saltStr = readString(contentTLV.get(tlv_salt));
uint64_t saltInt = std::stoull(saltStr);
m_ecdh.deriveSecret(peerKeyBase64Str);
@@ -221,22 +228,22 @@
(uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
// update state
- m_status = contentJson.get(JSON_CA_STATUS, 0);
- m_requestId = contentJson.get(JSON_CA_REQUEST_ID, "");
-
- auto challengesJson = contentJson.get_child(JSON_CA_CHALLENGES);
+ m_status = readNonNegativeInteger(contentTLV.get(tlv_status));
+ m_requestId = readString(contentTLV.get(tlv_request_id));
m_challengeList.clear();
- for (const auto& challengeJson : challengesJson) {
- m_challengeList.push_back(challengeJson.second.get(JSON_CA_CHALLENGE_ID, ""));
+ for (auto const& element : contentTLV.elements()) {
+ if (element.type() == tlv_challenge) {
+ m_challengeList.push_back(readString(element));
+ }
}
return m_challengeList;
}
shared_ptr<Interest>
-ClientModule::generateChallengeInterest(const JsonSection& paramJson)
+ClientModule::generateChallengeInterest(const Block& challengeRequest)
{
- m_challengeType = paramJson.get(JSON_CLIENT_SELECTED_CHALLENGE, "");
-
+ m_challengeType = readString(challengeRequest.get(tlv_selected_challenge));
+
Name interestName = m_ca.m_caName;
interestName.append("CA").append("CHALLENGE").append(m_requestId);
auto interest = make_shared<Interest>(interestName);
@@ -244,11 +251,9 @@
interest->setCanBePrefix(false);
// encrypt the Interest parameters
- std::stringstream ss;
- boost::property_tree::write_json(ss, paramJson);
- auto payload = ss.str();
+ auto payload = challengeRequest.getBuffer();
auto paramBlock = encodeBlockWithAesGcm128(tlv::ApplicationParameters, m_aesKey,
- (const uint8_t*)payload.c_str(), payload.size(), (const uint8_t*)"test", strlen("test"));
+ payload->data(), payload->size(), (const uint8_t*)"test", strlen("test"));
interest->setApplicationParameters(paramBlock);
m_keyChain.sign(*interest, signingByKey(m_key.getName()));
@@ -263,17 +268,19 @@
return;
}
auto result = decodeBlockWithAesGcm128(reply.getContent(), m_aesKey, (const uint8_t*)"test", strlen("test"));
- std::string payload((const char*)result.data(), result.size());
- std::istringstream ss(payload);
- JsonSection contentJson;
- boost::property_tree::json_parser::read_json(ss, contentJson);
+ bool isSuccess;
+ Block contentTLV;
+
+ std::tie<bool, Block>(isSuccess, contentTLV) = Block::fromBuffer(result.data(), result.size());
// update state
- m_status = contentJson.get(JSON_CA_STATUS, 0);
- m_challengeStatus = contentJson.get(JSON_CHALLENGE_STATUS, "");
- m_remainingTries = contentJson.get(JSON_CHALLENGE_REMAINING_TRIES, 0);
- m_freshBefore = time::system_clock::now() + time::seconds(contentJson.get(JSON_CHALLENGE_REMAINING_TIME, 0));
- m_issuedCertName = contentJson.get(JSON_CHALLENGE_ISSUED_CERT_NAME, "");
+ m_status = readNonNegativeInteger(contentTLV.get(tlv_status));
+ m_challengeStatus = readString(contentTLV.get(tlv_challenge_status));
+ m_remainingTries = readNonNegativeInteger(contentTLV.get(tlv_remaining_tries));
+ m_freshBefore = time::system_clock::now() +
+ time::seconds(readNonNegativeInteger(contentTLV.get(tlv_remaining_time)));
+
+ m_issuedCertName.wireDecode(contentTLV.get(tlv_issued_cert_name));
}
shared_ptr<Interest>
diff --git a/src/client-module.hpp b/src/client-module.hpp
index 57ae01f..f45b034 100644
--- a/src/client-module.hpp
+++ b/src/client-module.hpp
@@ -71,7 +71,7 @@
generateInfoInterest(const Name& caName);
bool
- verifyProbeInfoResponse(const Data& reply);
+ verifyInfoResponse(const Data& reply);
/**
* @brief Process the replied PROBE INFO Data packet
@@ -80,7 +80,7 @@
* can be verified in later challenge phase.
*/
void
- addCaFromProbeInfoResponse(const Data& reply);
+ addCaFromInfoResponse(const Data& reply);
shared_ptr<Interest>
generateProbeInterest(const ClientCaItem& ca, const std::string& probeInfo);
@@ -97,7 +97,7 @@
onNewResponse(const Data& reply);
shared_ptr<Interest>
- generateChallengeInterest(const JsonSection& paramJson);
+ generateChallengeInterest(const Block& paramTLV);
void
onChallengeResponse(const Data& reply);
@@ -145,7 +145,7 @@
std::string m_challengeStatus = "";
std::string m_challengeType = "";
std::string m_certId = "";
- std::string m_issuedCertName = "";
+ Name m_issuedCertName;
std::list<std::string> m_challengeList;
bool m_isCertInstalled = false;
bool m_isNewlyCreatedIdentity = false;
diff --git a/src/protocol-detail/challenge.cpp b/src/protocol-detail/challenge.cpp
new file mode 100644
index 0000000..f1fed27
--- /dev/null
+++ b/src/protocol-detail/challenge.cpp
@@ -0,0 +1,44 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, 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 "challenge.hpp"
+#include "../ndncert-common.hpp"
+#include "../certificate-request.hpp"
+
+namespace ndn {
+namespace ndncert {
+
+Block
+CHALLENGE::encodeDataPayload(const CertificateRequest& request)
+{
+ Block response = makeEmptyBlock(tlv_encrypted_payload);
+ makeNonNegativeIntegerBlock(tlv_status, request.m_status);
+ makeStringBlock(tlv_challenge_status, request.m_challengeStatus);
+ makeNonNegativeIntegerBlock(tlv_remaining_tries, request.m_remainingTries);
+ makeNonNegativeIntegerBlock(tlv_remaining_time, request.m_remainingTime);
+ response.parse();
+ return response;
+}
+
+} // namespace ndncert
+} // namespace ndn
+
+
+
diff --git a/src/protocol-detail/challenge.hpp b/src/protocol-detail/challenge.hpp
new file mode 100644
index 0000000..1ff74fd
--- /dev/null
+++ b/src/protocol-detail/challenge.hpp
@@ -0,0 +1,39 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, 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_PROTOCOL_DETAIL_CHALLENGE_HPP
+#define NDNCERT_PROTOCOL_DETAIL_CHALLENGE_HPP
+
+#include "../certificate-request.hpp"
+#include <ndn-cxx/encoding/block.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+class CHALLENGE {
+public:
+ static Block
+ encodeDataPayload(const CertificateRequest& request);
+};
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_PROTOCOL_DETAIL_HPP
\ No newline at end of file
diff --git a/src/protocol-detail/info.cpp b/src/protocol-detail/info.cpp
index 93bd7b7..1463e04 100644
--- a/src/protocol-detail/info.cpp
+++ b/src/protocol-detail/info.cpp
@@ -28,7 +28,14 @@
{
auto content = makeEmptyBlock(tlv::Content);
content.push_back(makeNestedBlock(tlv_ca_prefix, caConfig.m_caPrefix));
- content.push_back(makeStringBlock(tlv_ca_info, caConfig.m_caInfo));
+ std::string caInfo = "";
+ if (caConfig.m_caInfo == "") {
+ caInfo = "Issued by " + certificate.getSignature().getKeyLocator().getName().toUri();
+ } else {
+ caInfo = caConfig.m_caInfo;
+ }
+ content.push_back(makeStringBlock(tlv_ca_info, caInfo));
+
for (const auto& key : caConfig.m_probeParameterKeys) {
content.push_back(makeStringBlock(tlv_parameter_key, key));
}
diff --git a/src/protocol-detail/info.hpp b/src/protocol-detail/info.hpp
index 89a907b..9c190f2 100644
--- a/src/protocol-detail/info.hpp
+++ b/src/protocol-detail/info.hpp
@@ -18,8 +18,8 @@
* See AUTHORS.md for complete list of ndncert authors and contributors.
*/
-#ifndef NDNCERT_PROTOCOL_DETAIL_HPP
-#define NDNCERT_PROTOCOL_DETAIL_HPP
+#ifndef NDNCERT_PROTOCOL_DETAIL_INFO_HPP
+#define NDNCERT_PROTOCOL_DETAIL_INFO_HPP
#include "../ca-config.hpp"
#include "../client-config.hpp"
diff --git a/src/protocol-detail/new.cpp b/src/protocol-detail/new.cpp
new file mode 100644
index 0000000..27bbf0a
--- /dev/null
+++ b/src/protocol-detail/new.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, 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 "new.hpp"
+#include "../logging.hpp"
+#include "../ndncert-common.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>
+#include <ndn-cxx/util/logger.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+_LOG_INIT(ndncert.client);
+
+Block
+NEW::encodeApplicationParameters(const std::string& ecdhPub, const security::v2::Certificate& certRequest,
+ const shared_ptr<Data>& probeToken)
+{
+ Block request = makeEmptyBlock(tlv::ApplicationParameters);
+ std::stringstream ss;
+ try {
+ security::transform::bufferSource(certRequest.wireEncode().wire(), certRequest.wireEncode().size())
+ >> security::transform::base64Encode(false)
+ >> security::transform::streamSink(ss);
+ }
+ catch (const security::transform::Error& e) {
+ _LOG_ERROR("Cannot convert self-signed cert into BASE64 string " << e.what());
+ return request;
+ }
+
+ request.push_back(makeStringBlock(tlv_ecdh_pub, ecdhPub));
+ request.push_back(makeNestedBlock(tlv_cert_request, certRequest));
+ request.parse();
+ return request;
+}
+
+Block
+NEW::encodeDataContent(const std::string& ecdhKey, const std::string& salt,
+ const CertificateRequest& request,
+ const std::list<std::string>& challenges)
+{
+ Block response = makeEmptyBlock(tlv::Content);
+ response.push_back(makeStringBlock(tlv_ecdh_pub, ecdhKey));
+ response.push_back(makeStringBlock(tlv_salt, salt));
+ response.push_back(makeStringBlock(tlv_request_id, request.m_requestId));
+ response.push_back(makeNonNegativeIntegerBlock(tlv_status, request.m_status));
+ for (const auto& entry: challenges) {
+ response.push_back(makeStringBlock(tlv_challenge, entry));
+ }
+ response.parse();
+ return response;
+}
+
+} // namespace ndncert
+} // namespace ndn
\ No newline at end of file
diff --git a/src/protocol-detail/new.hpp b/src/protocol-detail/new.hpp
new file mode 100644
index 0000000..ae95a15
--- /dev/null
+++ b/src/protocol-detail/new.hpp
@@ -0,0 +1,46 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, 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_PROTOCOL_DETAIL_NEW_HPP
+#define NDNCERT_PROTOCOL_DETAIL_NEW_HPP
+
+#include "../certificate-request.hpp"
+#include "ndn-cxx/encoding/block.hpp"
+#include <ndn-cxx/security/v2/certificate.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+class NEW {
+public:
+ static Block
+ encodeApplicationParameters(const std::string& ecdhPub, const security::v2::Certificate& certRequest,
+ const shared_ptr<Data>& probeToken);
+
+ static Block
+ encodeDataContent(const std::string& ecdhKey, const std::string& salt,
+ const CertificateRequest& request,
+ const std::list<std::string>& challenges);
+};
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_PROTOCOL_DETAIL_HPP
\ No newline at end of file
diff --git a/src/protocol-detail/probe.cpp b/src/protocol-detail/probe.cpp
new file mode 100644
index 0000000..b8034b1
--- /dev/null
+++ b/src/protocol-detail/probe.cpp
@@ -0,0 +1,99 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, 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 "probe.hpp"
+#include "boost/throw_exception.hpp"
+#include "../logging.hpp"
+#include <ndn-cxx/encoding/tlv.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+// For Client
+std::vector<std::string>
+PROBE::parseProbeComponents(const std::string& probe)
+{
+ std::vector<std::string> components;
+ std::string delimiter = ":";
+ size_t last = 0;
+ size_t next = 0;
+ while ((next = probe.find(delimiter, last)) != std::string::npos) {
+ components.push_back(probe.substr(last, next - last));
+ last = next + 1;
+ }
+ components.push_back(probe.substr(last));
+ return components;
+}
+
+Block
+PROBE::encodeApplicationParametersFromProbeInfo(const ClientCaItem& ca, const std::string& probeInfo)
+{
+ auto content = makeEmptyBlock(tlv::ApplicationParameters);
+
+ std::vector<std::string> fields = parseProbeComponents(ca.m_probe);
+ std::vector<std::string> arguments = parseProbeComponents(probeInfo);;
+
+ if (arguments.size() != fields.size()) {
+ BOOST_THROW_EXCEPTION(Error("Error in genProbeRequestJson: argument list does not match field list in the config file."));
+ }
+
+ for (size_t i = 0; i < fields.size(); ++i) {
+ content.push_back(
+ makeStringBlock(tlv_parameter_key, fields.at(i))
+ );
+ content.push_back(
+ makeStringBlock(tlv_parameter_value, arguments.at(i))
+ );
+ }
+ content.parse();
+ return content;
+}
+
+// For CA
+Block
+PROBE::encodeDataContent(const Name& identifier, const std::string& m_probe, const Block& parameterTLV)
+{
+ std::vector<std::string> fields;
+ std::string delimiter = ":";
+ size_t last = 0;
+ size_t next = 0;
+ while ((next = m_probe.find(delimiter, last)) != std::string::npos) {
+ fields.push_back(m_probe.substr(last, next - last));
+ last = next + 1;
+ }
+ fields.push_back(m_probe.substr(last));
+
+ Block content = makeEmptyBlock(tlv::Content);
+
+ // TODO: Currently have no mechanism to utilize the given params to determine name
+ //for (size_t i = 0; i < fields.size(); ++i) {
+ // root.put(fields.at(i), parameterJson.get(fields.at(i), ""));
+ //}
+
+ content.push_back(makeNestedBlock(tlv_probe_response, identifier));
+
+ // TODO: Must be determined based on CA config
+ content.push_back(makeEmptyBlock(tlv_allow_longer_name));
+ content.parse();
+ return content;
+}
+
+} // namespace ndncert
+} // namespace ndn
\ No newline at end of file
diff --git a/src/protocol-detail/probe.hpp b/src/protocol-detail/probe.hpp
new file mode 100644
index 0000000..6fbca8e
--- /dev/null
+++ b/src/protocol-detail/probe.hpp
@@ -0,0 +1,56 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2017-2020, 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_PROTOCOL_DETAIL_PROBE_HPP
+#define NDNCERT_PROTOCOL_DETAIL_PROBE_HPP
+
+#include "../ca-config.hpp"
+#include "../client-config.hpp"
+
+namespace ndn {
+namespace ndncert {
+
+class PROBE {
+
+public:
+ /**
+ * @brief Error that can be thrown from PROBE
+ */
+ class Error : public std::runtime_error
+ {
+ public:
+ using std::runtime_error::runtime_error;
+ };
+
+public:
+ static std::vector<std::string>
+ parseProbeComponents(const std::string& probe);
+
+ static Block
+ encodeApplicationParametersFromProbeInfo(const ClientCaItem& ca, const std::string& probeInfo);
+
+ static Block
+ encodeDataContent(const Name& identifier, const std::string& m_probe, const Block& parameterTLV);
+};
+
+} // namespace ndncert
+} // namespace ndn
+
+#endif // NDNCERT_PROTOCOL_DETAIL_HPP
\ No newline at end of file