improve the robustness of ndncert library
Change-Id: Iaabc4d8f28ca27a7e7f501ebd122c5231ceb3ac0
diff --git a/src/ca-config.cpp b/src/ca-config.cpp
index 3165b2d..3145839 100644
--- a/src/ca-config.cpp
+++ b/src/ca-config.cpp
@@ -19,6 +19,7 @@
*/
#include "ca-config.hpp"
+#include "challenge-module.hpp"
#include <ndn-cxx/util/io.hpp>
#include <boost/filesystem.hpp>
@@ -32,9 +33,8 @@
try {
boost::property_tree::read_json(fileName, configJson);
}
- catch (const boost::property_tree::info_parser_error& error) {
- BOOST_THROW_EXCEPTION(Error("Failed to parse configuration file " + fileName +
- " " + error.message() + " line " + std::to_string(error.line())));
+ catch (const std::exception& error) {
+ BOOST_THROW_EXCEPTION(Error("Failed to parse configuration file " + fileName + ", " + error.what()));
}
if (configJson.begin() == configJson.end()) {
@@ -46,18 +46,21 @@
void
CaConfig::parse(const JsonSection& configJson)
{
- // essential info
- 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));
+ // essential info
+ m_caName = Name(configJson.get("ca-prefix", ""));
+ if (m_caName.empty()) {
+ BOOST_THROW_EXCEPTION(Error("Cannot read ca-prefix from the config file"));
+ }
+ m_freshnessPeriod = time::seconds(configJson.get("issuing-freshness", 720));
+ m_validityPeriod = time::days(configJson.get("max-validity-period", 360));
- // optional info
- m_probe = configJson.get("probe", "");
- m_caInfo = configJson.get("ca-info", "");
+ // optional info
+ m_probe = configJson.get("probe", "");
+ m_caInfo = configJson.get("ca-info", "");
- // optional supported challenges
- auto challengeList = configJson.get_child("supported-challenges");
- m_supportedChallenges = parseChallengeList(challengeList);
+ // optional supported challenges
+ auto challengeList = configJson.get_child("supported-challenges");
+ m_supportedChallenges = parseChallengeList(challengeList);
}
std::list<std::string>
@@ -66,7 +69,15 @@
std::list<std::string> result;
auto it = section.begin();
for (; it != section.end(); it++) {
- result.push_back(boost::algorithm::to_lower_copy(it->second.get<std::string>("type")));
+ auto challengeType = it->second.get("type", "");
+ if (challengeType == "") {
+ BOOST_THROW_EXCEPTION(Error("Cannot read type in supported-challenges from the config file"));
+ }
+ challengeType = boost::algorithm::to_lower_copy(challengeType);
+ if (!ChallengeModule::supportChallenge(challengeType)) {
+ BOOST_THROW_EXCEPTION(Error("Does not support challenge read from the config file"));
+ }
+ result.push_back(challengeType);
}
return result;
}
diff --git a/src/ca-config.hpp b/src/ca-config.hpp
index e20b8b4..0186067 100644
--- a/src/ca-config.hpp
+++ b/src/ca-config.hpp
@@ -65,6 +65,12 @@
};
public:
+ /**
+ * @throw CaConfig::Error when config file does not exist
+ * @throw CaConfig::Error when the JSON text in the file cannot be parsed correctly
+ * @throw CaConfig::Error when the ca-prefix attribute in JSON text is empty
+ * @throw CaConfig::Error when the challenge is not specified or is not supported
+ */
void
load(const std::string& fileName);
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index 89bf8a7..7dbb053 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -340,7 +340,7 @@
}
// load the corresponding challenge module
- std::string challengeType = paramJson.get<std::string>(JSON_CLIENT_SELECTED_CHALLENGE);
+ std::string challengeType = paramJson.get(JSON_CLIENT_SELECTED_CHALLENGE, "");
auto challenge = ChallengeModule::createChallengeModule(challengeType);
JsonSection contentJson;
if (challenge == nullptr) {
diff --git a/src/ca-module.hpp b/src/ca-module.hpp
index 3926d97..0b857b0 100644
--- a/src/ca-module.hpp
+++ b/src/ca-module.hpp
@@ -121,7 +121,7 @@
std::list<InterestFilterHandle> m_interestFilterHandles;
ECDHState m_ecdh;
- uint8_t m_aesKey[32] = {0};
+ uint8_t m_aesKey[16] = {0};
};
} // namespace ndncert
diff --git a/src/challenge-module.cpp b/src/challenge-module.cpp
index 8c332cb..9288330 100644
--- a/src/challenge-module.cpp
+++ b/src/challenge-module.cpp
@@ -31,11 +31,19 @@
ChallengeModule::~ChallengeModule() = default;
-unique_ptr<ChallengeModule>
-ChallengeModule::createChallengeModule(const std::string& canonicalName)
+bool
+ChallengeModule::supportChallenge(const std::string& challengeType)
{
ChallengeFactory& factory = getFactory();
- auto i = factory.find(canonicalName);
+ auto i = factory.find(challengeType);
+ return i == factory.end() ? false : true;
+}
+
+unique_ptr<ChallengeModule>
+ChallengeModule::createChallengeModule(const std::string& challengeType)
+{
+ ChallengeFactory& factory = getFactory();
+ auto i = factory.find(challengeType);
return i == factory.end() ? nullptr : i->second();
}
diff --git a/src/challenge-module.hpp b/src/challenge-module.hpp
index ab15be8..80670f4 100644
--- a/src/challenge-module.hpp
+++ b/src/challenge-module.hpp
@@ -58,8 +58,11 @@
factory[typeName] = [] { return make_unique<ChallengeType>(); };
}
+ static bool
+ supportChallenge(const std::string& challengeType);
+
static unique_ptr<ChallengeModule>
- createChallengeModule(const std::string& ChallengeType);
+ createChallengeModule(const std::string& challengeType);
// For CA
virtual void
diff --git a/src/challenge-module/challenge-credential.cpp b/src/challenge-module/challenge-credential.cpp
index 839ccae..f5d7434 100644
--- a/src/challenge-module/challenge-credential.cpp
+++ b/src/challenge-module/challenge-credential.cpp
@@ -41,8 +41,9 @@
if (configPath == "") {
m_configFile = std::string(SYSCONFDIR) + "/ndncert/challenge-credential.conf";
}
- else
+ else {
m_configFile = configPath;
+ }
}
void
@@ -65,9 +66,13 @@
auto anchorList = config.get_child("anchor-list");
auto it = anchorList.begin();
for (; it != anchorList.end(); it++) {
- std::istringstream ss(it->second.get<std::string>("certificate"));
- security::v2::Certificate cert = *(io::load<security::v2::Certificate>(ss));
- m_trustAnchors.push_back(cert);
+ std::istringstream ss(it->second.get("certificate", ""));
+ auto cert = io::load<security::v2::Certificate>(ss);
+ if (cert == nullptr) {
+ _LOG_ERROR("Cannot load the certificate from config file");
+ continue;
+ }
+ m_trustAnchors.push_back(*cert);
}
}
@@ -79,13 +84,10 @@
parseConfigFile();
}
// 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_ERROR("Cannot load credential parameter: cert" << e.what());
+ std::istringstream ss1(params.get(JSON_CREDENTIAL_CERT, ""));
+ auto cert = io::load<security::v2::Certificate>(ss1);
+ if (cert == nullptr) {
+ _LOG_ERROR("Cannot load credential parameter: cert");
request.m_status = STATUS_FAILURE;
request.m_challengeStatus = FAILURE_INVALID_FORMAT_CREDENTIAL;
updateRequestOnChallengeEnd(request);
@@ -94,13 +96,10 @@
ss1.str("");
ss1.clear();
// load self-signed data
- std::istringstream ss2(params.get<std::string>(JSON_CREDENTIAL_SELF));
- Data self;
- try {
- self = *(io::load<Data>(ss2));
- }
- catch (const std::exception& e) {
- _LOG_TRACE("Cannot load credential parameter: self-signed cert" << e.what());
+ std::istringstream ss2(params.get(JSON_CREDENTIAL_SELF, ""));
+ auto self = io::load<Data>(ss2);
+ if (self == nullptr) {
+ _LOG_TRACE("Cannot load credential parameter: self-signed cert");
request.m_status = STATUS_FAILURE;
request.m_challengeStatus = FAILURE_INVALID_FORMAT_SELF_SIGNED;
updateRequestOnChallengeEnd(request);
@@ -110,11 +109,11 @@
ss2.clear();
// verify the credential and the self-signed cert
- Name signingKeyName = cert.getSignature().getKeyLocator().getName();
+ Name signingKeyName = cert->getSignature().getKeyLocator().getName();
for (auto anchor : m_trustAnchors) {
if (anchor.getKeyName() == signingKeyName) {
- if (security::verifySignature(cert, anchor) && security::verifySignature(self, cert)
- && readString(self.getContent()) == request.m_requestId) {
+ 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);
@@ -150,8 +149,8 @@
{
JsonSection result;
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, ""));
+ result.put(JSON_CREDENTIAL_CERT, params.get(JSON_CREDENTIAL_CERT, ""));
+ result.put(JSON_CREDENTIAL_SELF, params.get(JSON_CREDENTIAL_SELF, ""));
}
else {
_LOG_ERROR("Client's status and challenge status are wrong");
diff --git a/src/challenge-module/challenge-email.cpp b/src/challenge-module/challenge-email.cpp
index b22ec93..b9ca344 100644
--- a/src/challenge-module/challenge-email.cpp
+++ b/src/challenge-module/challenge-email.cpp
@@ -50,9 +50,10 @@
void
ChallengeEmail::handleChallengeRequest(const JsonSection& 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<std::string>(JSON_EMAIL);
+ std::string emailAddress = params.get(JSON_EMAIL, "");
if (!isValidEmailAddress(emailAddress)) {
request.m_status = STATUS_FAILURE;
request.m_challengeStatus = FAILURE_INVALID_EMAIL;
@@ -79,7 +80,7 @@
JsonSection secretJson;
secretJson.add(JSON_CODE, emailCode);
request.m_challengeSecrets = secretJson;
- request.m_challengeTp = time::toIsoString(time::system_clock::now());
+ request.m_challengeTp = time::toIsoString(currentTime);
request.m_remainingTime = m_secretLifetime.count();
request.m_remainingTries = m_maxAttemptTimes;
// send out the email
@@ -90,9 +91,9 @@
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);
+ std::string givenCode = params.get(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) {
+ if (currentTime - time::fromIsoString(request.m_challengeTp) >= m_secretLifetime) {
// secret expires
request.m_status = STATUS_FAILURE;
request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_TIMEOUT;
@@ -113,7 +114,7 @@
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));
+ auto remainTime = m_secretLifetime - (currentTime - time::fromIsoString(request.m_challengeTp));
request.m_remainingTime = remainTime.count();
_LOG_TRACE("Secret code didn't match. Remaining Tries - 1.");
return;
@@ -161,15 +162,15 @@
JsonSection result;
if (status == STATUS_BEFORE_CHALLENGE && challengeStatus == "") {
result.put(JSON_CLIENT_SELECTED_CHALLENGE, CHALLENGE_TYPE);
- result.put(JSON_EMAIL, params.get<std::string>(JSON_EMAIL, ""));
+ result.put(JSON_EMAIL, params.get(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, ""));
+ result.put(JSON_CODE, params.get(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, ""));
+ result.put(JSON_CODE, params.get(JSON_CODE, ""));
}
else {
_LOG_ERROR("Client's status and challenge status are wrong");
diff --git a/src/challenge-module/challenge-pin.cpp b/src/challenge-module/challenge-pin.cpp
index 9534b21..87f36cc 100644
--- a/src/challenge-module/challenge-pin.cpp
+++ b/src/challenge-module/challenge-pin.cpp
@@ -44,6 +44,7 @@
void
ChallengePin::handleChallengeRequest(const JsonSection& params, CertificateRequest& request)
{
+ auto currentTime = time::system_clock::now();
if (request.m_challengeStatus == "") {
_LOG_TRACE("Challenge Interest arrives. Init the challenge");
// for the first time, init the challenge
@@ -54,7 +55,7 @@
JsonSection secretJson;
secretJson.add(JSON_PIN_CODE, secretCode);
request.m_challengeSecrets = secretJson;
- request.m_challengeTp = time::toIsoString(time::system_clock::now());
+ request.m_challengeTp = time::toIsoString(currentTime);
request.m_remainingTime = m_secretLifetime.count();
request.m_remainingTries = m_maxAttemptTimes;
_LOG_TRACE("Secret for request " << request.m_requestId << " : " << secretCode);
@@ -63,9 +64,9 @@
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);
+ std::string givenCode = params.get(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) {
+ if (currentTime - time::fromIsoString(request.m_challengeTp) >= m_secretLifetime) {
// secret expires
request.m_status = STATUS_FAILURE;
request.m_challengeStatus = CHALLENGE_STATUS_FAILURE_TIMEOUT;
@@ -86,7 +87,7 @@
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));
+ auto remainTime = m_secretLifetime - (currentTime - time::fromIsoString(request.m_challengeTp));
request.m_remainingTime = remainTime.count();
_LOG_TRACE("PIN code didn't match. Remaining Tries - 1.");
return;
@@ -138,11 +139,11 @@
}
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, ""));
+ result.put(JSON_PIN_CODE, params.get(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, ""));
+ result.put(JSON_PIN_CODE, params.get(JSON_PIN_CODE, ""));
}
else {
_LOG_ERROR("Client's status and challenge status are wrong");
diff --git a/src/client-config.cpp b/src/client-config.cpp
index 19f8a89..1cd2618 100644
--- a/src/client-config.cpp
+++ b/src/client-config.cpp
@@ -32,13 +32,12 @@
try {
boost::property_tree::read_json(fileName, config);
}
- catch (const boost::property_tree::info_parser_error& error) {
- BOOST_THROW_EXCEPTION(Error("Failed to parse configuration file " + fileName +
- " " + error.message() + " line " + std::to_string(error.line())));
+ catch (const std::exception& error) {
+ BOOST_THROW_EXCEPTION(Error("Failed to parse configuration file " + fileName + ", " + error.what()));
}
if (config.begin() == config.end()) {
- BOOST_THROW_EXCEPTION(Error("Error processing configuration file: " + fileName + " no data"));
+ BOOST_THROW_EXCEPTION(Error("Error processing configuration file: " + fileName + ", no data"));
}
load(config);
@@ -86,11 +85,18 @@
ClientConfig::extractCaItem(const JsonSection& configSection)
{
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<std::string>("probe");
- std::istringstream ss(configSection.get<std::string>("certificate"));
- item.m_anchor = *(io::load<security::v2::Certificate>(ss));
+ 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 = 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"));
+ }
+ item.m_anchor = *anchor;
return item;
}
diff --git a/src/client-config.hpp b/src/client-config.hpp
index ba02efa..ba63e82 100644
--- a/src/client-config.hpp
+++ b/src/client-config.hpp
@@ -61,6 +61,12 @@
};
public:
+ /**
+ * @throw ClientConfig::Error when config file does not exist
+ * @throw ClientConfig::Error when the JSON text in the file cannot be parsed correctly
+ * @throw ClientConfig::Error when the ca-prefix attribute in JSON text is empty
+ * @throw ClientConfig::Error when the certificate in JSON text cannot be parsed correctly
+ */
void
load(const std::string& fileName);
diff --git a/src/client-module.cpp b/src/client-module.cpp
index 24947f4..9ae71c0 100644
--- a/src/client-module.cpp
+++ b/src/client-module.cpp
@@ -116,7 +116,7 @@
auto contentJson = getJsonFromData(reply);
// read the available name and put it into the state
- auto nameUri = contentJson.get<std::string>(JSON_CA_NAME, "");
+ auto nameUri = contentJson.get(JSON_CA_NAME, "");
if (nameUri != "") {
m_identityName = Name(nameUri);
}
@@ -200,8 +200,8 @@
auto contentJson = getJsonFromData(reply);
// ECDH
- const auto& peerKeyBase64Str = contentJson.get<std::string>(JSON_CA_ECDH, "");
- const auto& saltStr = contentJson.get<std::string>(JSON_CA_SALT, "");
+ const auto& peerKeyBase64Str = contentJson.get(JSON_CA_ECDH, "");
+ const auto& saltStr = contentJson.get(JSON_CA_SALT, "");
uint64_t saltInt = std::stoull(saltStr);
m_ecdh.deriveSecret(peerKeyBase64Str);
@@ -210,13 +210,13 @@
(uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
// update state
- m_status = contentJson.get<int>(JSON_CA_STATUS);
- m_requestId = contentJson.get<std::string>(JSON_CA_REQUEST_ID, "");
+ 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_challengeList.clear();
for (const auto& challengeJson : challengesJson) {
- m_challengeList.push_back(challengeJson.second.get<std::string>(JSON_CA_CHALLENGE_ID, ""));
+ m_challengeList.push_back(challengeJson.second.get(JSON_CA_CHALLENGE_ID, ""));
}
return m_challengeList;
}
@@ -224,7 +224,7 @@
shared_ptr<Interest>
ClientModule::generateChallengeInterest(const JsonSection& paramJson)
{
- m_challengeType = paramJson.get<std::string>(JSON_CLIENT_SELECTED_CHALLENGE);
+ m_challengeType = paramJson.get(JSON_CLIENT_SELECTED_CHALLENGE, "");
Name interestName = m_ca.m_caName;
interestName.append("CA").append("_CHALLENGE").append(m_requestId);
@@ -258,10 +258,10 @@
boost::property_tree::json_parser::read_json(ss, contentJson);
// 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));
+ 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));
}
shared_ptr<Interest>
@@ -355,7 +355,7 @@
std::stringstream ss;
try {
security::transform::bufferSource(certRequest.wireEncode().wire(), certRequest.wireEncode().size())
- >> security::transform::base64Encode(true)
+ >> security::transform::base64Encode(false)
>> security::transform::streamSink(ss);
}
catch (const security::transform::Error& e) {
@@ -371,7 +371,7 @@
// transform the probe data into a base64 string
try {
security::transform::bufferSource(probeToken->wireEncode().wire(), probeToken->wireEncode().size())
- >> security::transform::base64Encode(true)
+ >> security::transform::base64Encode(false)
>> security::transform::streamSink(ss);
}
catch (const security::transform::Error& e) {
diff --git a/src/client-module.hpp b/src/client-module.hpp
index 806c5bc..b3655ef 100644
--- a/src/client-module.hpp
+++ b/src/client-module.hpp
@@ -153,7 +153,7 @@
time::system_clock::TimePoint m_freshBefore;
ECDHState m_ecdh;
- uint8_t m_aesKey[32] = {0};
+ uint8_t m_aesKey[16] = {0};
};
} // namespace ndncert
diff --git a/src/crypto-support/crypto-helper.cpp b/src/crypto-support/crypto-helper.cpp
index ea18dba..0792bfc 100644
--- a/src/crypto-support/crypto-helper.cpp
+++ b/src/crypto-support/crypto-helper.cpp
@@ -148,7 +148,7 @@
std::ostringstream os;
t::bufferSource(context->publicKey, context->publicKeyLen)
- >> t::base64Encode()
+ >> t::base64Encode(false)
>> t::streamSink(os);
return os.str();
}
@@ -159,19 +159,24 @@
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().");
+ 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))) {
+ int result = EC_POINT_oct2point(group, peerPoint, peerkey, peerKeySize, nullptr);
+ if (result == 0) {
EC_POINT_free(peerPoint);
EC_KEY_free(privECKey);
- handleErrors("Cannot generate ECDH secret with ECDH_compute_key");
+ handleErrors("Cannot convert peer's key into a EC point when calling EC_POINT_oct2point()");
+ }
+
+ if (-1 == (context->sharedSecretLen = ECDH_compute_key(context->sharedSecret, 256,
+ peerPoint, privECKey, nullptr))) {
+ EC_POINT_free(peerPoint);
+ EC_KEY_free(privECKey);
+ handleErrors("Cannot generate ECDH secret when calling ECDH_compute_key()");
}
EC_POINT_free(peerPoint);
EC_KEY_free(privECKey);
@@ -184,7 +189,7 @@
namespace t = ndn::security::transform;
OBufferStream os;
- t::bufferSource(peerKeyStr) >> t::base64Decode() >> t::streamSink(os);
+ t::bufferSource(peerKeyStr) >> t::base64Decode(false) >> t::streamSink(os);
auto result = os.buf();
return this->deriveSecret(result->data(), result->size());
diff --git a/tests/unit-tests/ca-config.t.cpp b/tests/unit-tests/ca-config.t.cpp
index 0cebb26..5b47505 100644
--- a/tests/unit-tests/ca-config.t.cpp
+++ b/tests/unit-tests/ca-config.t.cpp
@@ -32,7 +32,7 @@
BOOST_FIXTURE_TEST_SUITE(TestCaConfig, IdentityManagementFixture)
-BOOST_AUTO_TEST_CASE(ReadConfigFileWithFileAnchor)
+BOOST_AUTO_TEST_CASE(ReadConfigFile)
{
CaConfig config;
config.load("tests/unit-tests/ca.conf.test");
@@ -43,6 +43,24 @@
BOOST_CHECK_EQUAL(config.m_caInfo, "ndn testbed ca");
}
+BOOST_AUTO_TEST_CASE(ReadNonexistConfigFile)
+{
+ CaConfig config;
+ BOOST_CHECK_THROW(config.load("tests/unit-tests/Nonexist"), CaConfig::Error);
+}
+
+BOOST_AUTO_TEST_CASE(ReadConfigFileWithoutCaPrefix)
+{
+ CaConfig config;
+ BOOST_CHECK_THROW(config.load("tests/unit-tests/ca.conf.test2"), CaConfig::Error);
+}
+
+BOOST_AUTO_TEST_CASE(ReadConfigFileWithChallengeNotSupported)
+{
+ CaConfig config;
+ BOOST_CHECK_THROW(config.load("tests/unit-tests/ca.conf.test3"), CaConfig::Error);
+}
+
BOOST_AUTO_TEST_SUITE_END() // TestCaConfig
} // namespace tests
diff --git a/tests/unit-tests/ca-module.t.cpp b/tests/unit-tests/ca-module.t.cpp
index 374c847..a72a3d8 100644
--- a/tests/unit-tests/ca-module.t.cpp
+++ b/tests/unit-tests/ca-module.t.cpp
@@ -179,7 +179,8 @@
BOOST_CHECK(challengesJson.size() != 0);
client.onNewResponse(response);
- BOOST_CHECK_EQUAL_COLLECTIONS(client.m_aesKey, client.m_aesKey + 32, ca.m_aesKey, ca.m_aesKey + 32);
+ BOOST_CHECK_EQUAL_COLLECTIONS(client.m_aesKey, client.m_aesKey + sizeof(client.m_aesKey),
+ ca.m_aesKey, ca.m_aesKey + sizeof(ca.m_aesKey));
});
face.receive(*interest);
diff --git a/tests/unit-tests/ca.conf.test2 b/tests/unit-tests/ca.conf.test2
new file mode 100644
index 0000000..17f058b
--- /dev/null
+++ b/tests/unit-tests/ca.conf.test2
@@ -0,0 +1,9 @@
+{
+ "issuing-freshness": "720",
+ "validity-period": "360",
+ "ca-info": "ndn testbed ca",
+ "supported-challenges":
+ [
+ { "type": "PIN" }
+ ]
+}
\ No newline at end of file
diff --git a/tests/unit-tests/ca.conf.test3 b/tests/unit-tests/ca.conf.test3
new file mode 100644
index 0000000..f12eabb
--- /dev/null
+++ b/tests/unit-tests/ca.conf.test3
@@ -0,0 +1,10 @@
+{
+ "ca-prefix": "/ndn",
+ "issuing-freshness": "720",
+ "validity-period": "360",
+ "ca-info": "ndn testbed ca",
+ "supported-challenges":
+ [
+ { "type": "PINN" }
+ ]
+}
\ No newline at end of file
diff --git a/tests/unit-tests/client-config.t.cpp b/tests/unit-tests/client-config.t.cpp
index 5d662ff..0f8aa95 100644
--- a/tests/unit-tests/client-config.t.cpp
+++ b/tests/unit-tests/client-config.t.cpp
@@ -44,6 +44,24 @@
BOOST_CHECK_EQUAL(config.m_localNdncertAnchor, "/usr/local/etc/ndncert/anchor.key");
}
+BOOST_AUTO_TEST_CASE(ReadNonexistConfigFile)
+{
+ ClientConfig config;
+ BOOST_CHECK_THROW(config.load("tests/unit-tests/nonexist"), ClientConfig::Error);
+}
+
+BOOST_AUTO_TEST_CASE(ReadConfigFileWithInvalidCert)
+{
+ ClientConfig config;
+ BOOST_CHECK_THROW(config.load("tests/unit-tests/client.conf.test2"), ClientConfig::Error);
+}
+
+BOOST_AUTO_TEST_CASE(ReadConfigFileWithoutCaPrefix)
+{
+ ClientConfig config;
+ BOOST_CHECK_THROW(config.load("tests/unit-tests/client.conf.test3"), ClientConfig::Error);
+}
+
BOOST_AUTO_TEST_CASE(AddAndRemoveCaItem)
{
ClientConfig config;
diff --git a/tests/unit-tests/client.conf.test2 b/tests/unit-tests/client.conf.test2
new file mode 100644
index 0000000..f3d5630
--- /dev/null
+++ b/tests/unit-tests/client.conf.test2
@@ -0,0 +1,18 @@
+{
+ "ca-list":
+ [
+ {
+ "ca-prefix": "/ndn/edu/ucla",
+ "ca-info": "UCLA's ceritificate authority, located in BH4805.",
+ "probe": "email",
+ "certificate": "ANuZG4IBXNpdGUxCANLRVkICBG8IvRjFf8XCARzZWxmCAn9AAABWcgU2aUUCRgBAhkEADbugBX9AU8wggFLMIIBAwYHKoZIzj0CATCB9wIBATAsBgcqhkjOPQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wWwQg/////wAAAAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQawzFOw9jvOPD4n0mBLAxUAxJ02CIbnBJNqZnjhE50mt4GffpAEQQRrF9Hy4SxCR/i85uVjpEDydwN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQEDQgAES9Cb9iANUNYmwt5bjwNW1mZgjzIkDJb6FTCdiYWnkMMIVxh2YDllphoWDEAPS6kqJczzCuhnGYpZCp9tTaYKGxZMGwEDHB0HGwgDbmRuCAVzaXRlMQgDS0VZCAgRvCL0YxX/F/0A/Sb9AP4PMTk3MDAxMDFUMDAwMDAw/QD/DzIwMzcwMTE3VDIxMjg0NhdIMEYCIQDXkR1hF3GiP7yLXq+0JBJfi9QC+hhAu/1Bykx+MWz6RAIhANwelBTxxZr2C5bD15mjfhWudK4I1tOb4b/9xWCHyM7F"
+ },
+ {
+ "ca-prefix": "/ndn/edu/ucla/zhiyi",
+ "ca-info": "Zhiyi's own ceritificate authority",
+ "probe": "email",
+ "certificate": "Bv0CJAcsCANuZG4IBXNpdGUxCANLRVkICBG8IvRjFf8XCARzZWxmCAn9AAABWcgU2aUUCRgBAhkEADbugBX9AU8wggFLMIIBAwYHKoZIzj0CATCB9wIBATAsBgcqhkjOPQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wWwQg/////wAAAAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQawzFOw9jvOPD4n0mBLAxUAxJ02CIbnBJNqZnjhE50mt4GffpAEQQRrF9Hy4SxCR/i85uVjpEDydwN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQEDQgAES9Cb9iANUNYmwt5bjwNW1mZgjzIkDJb6FTCdiYWnkMMIVxh2YDllphoWDEAPS6kqJczzCuhnGYpZCp9tTaYKGxZMGwEDHB0HGwgDbmRuCAVzaXRlMQgDS0VZCAgRvCL0YxX/F/0A/Sb9AP4PMTk3MDAxMDFUMDAwMDAw/QD/DzIwMzcwMTE3VDIxMjg0NhdIMEYCIQDXkR1hF3GiP7yLXq+0JBJfi9QC+hhAu/1Bykx+MWz6RAIhANwelBTxxZr2C5bD15mjfhWudK4I1tOb4b/9xWCHyM7F"
+ }
+ ],
+ "local-ndncert-anchor": "/usr/local/etc/ndncert/anchor.key"
+}
\ No newline at end of file
diff --git a/tests/unit-tests/client.conf.test3 b/tests/unit-tests/client.conf.test3
new file mode 100644
index 0000000..257850a
--- /dev/null
+++ b/tests/unit-tests/client.conf.test3
@@ -0,0 +1,17 @@
+{
+ "ca-list":
+ [
+ {
+ "ca-info": "UCLA's ceritificate authority, located in BH4805.",
+ "probe": "email",
+ "certificate": "ANuZG4IBXNpdGUxCANLRVkICBG8IvRjFf8XCARzZWxmCAn9AAABWcgU2aUUCRgBAhkEADbugBX9AU8wggFLMIIBAwYHKoZIzj0CATCB9wIBATAsBgcqhkjOPQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wWwQg/////wAAAAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQawzFOw9jvOPD4n0mBLAxUAxJ02CIbnBJNqZnjhE50mt4GffpAEQQRrF9Hy4SxCR/i85uVjpEDydwN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQEDQgAES9Cb9iANUNYmwt5bjwNW1mZgjzIkDJb6FTCdiYWnkMMIVxh2YDllphoWDEAPS6kqJczzCuhnGYpZCp9tTaYKGxZMGwEDHB0HGwgDbmRuCAVzaXRlMQgDS0VZCAgRvCL0YxX/F/0A/Sb9AP4PMTk3MDAxMDFUMDAwMDAw/QD/DzIwMzcwMTE3VDIxMjg0NhdIMEYCIQDXkR1hF3GiP7yLXq+0JBJfi9QC+hhAu/1Bykx+MWz6RAIhANwelBTxxZr2C5bD15mjfhWudK4I1tOb4b/9xWCHyM7F"
+ },
+ {
+ "ca-prefix": "/ndn/edu/ucla/zhiyi",
+ "ca-info": "Zhiyi's own ceritificate authority",
+ "probe": "email",
+ "certificate": "Bv0CJAcsCANuZG4IBXNpdGUxCANLRVkICBG8IvRjFf8XCARzZWxmCAn9AAABWcgU2aUUCRgBAhkEADbugBX9AU8wggFLMIIBAwYHKoZIzj0CATCB9wIBATAsBgcqhkjOPQEBAiEA/////wAAAAEAAAAAAAAAAAAAAAD///////////////8wWwQg/////wAAAAEAAAAAAAAAAAAAAAD///////////////wEIFrGNdiqOpPns+u9VXaYhrxlHQawzFOw9jvOPD4n0mBLAxUAxJ02CIbnBJNqZnjhE50mt4GffpAEQQRrF9Hy4SxCR/i85uVjpEDydwN9gS3rM6D0oTlF2JjClk/jQuL+Gn+bjufrSnwPnhYrzjNXazFezsu2QGg3v1H1AiEA/////wAAAAD//////////7zm+q2nF56E87nKwvxjJVECAQEDQgAES9Cb9iANUNYmwt5bjwNW1mZgjzIkDJb6FTCdiYWnkMMIVxh2YDllphoWDEAPS6kqJczzCuhnGYpZCp9tTaYKGxZMGwEDHB0HGwgDbmRuCAVzaXRlMQgDS0VZCAgRvCL0YxX/F/0A/Sb9AP4PMTk3MDAxMDFUMDAwMDAw/QD/DzIwMzcwMTE3VDIxMjg0NhdIMEYCIQDXkR1hF3GiP7yLXq+0JBJfi9QC+hhAu/1Bykx+MWz6RAIhANwelBTxxZr2C5bD15mjfhWudK4I1tOb4b/9xWCHyM7F"
+ }
+ ],
+ "local-ndncert-anchor": "/usr/local/etc/ndncert/anchor.key"
+}
\ No newline at end of file
diff --git a/tests/unit-tests/crypto-helper.t.cpp b/tests/unit-tests/crypto-helper.t.cpp
index eda32d1..b6f8bd3 100644
--- a/tests/unit-tests/crypto-helper.t.cpp
+++ b/tests/unit-tests/crypto-helper.t.cpp
@@ -49,6 +49,16 @@
bobResult, bobResult + 32);
}
+BOOST_AUTO_TEST_CASE(EcdhWithRawKeyWrongInput)
+{
+ ECDHState aliceState;
+ auto alicePub = aliceState.getRawSelfPubKey();
+ BOOST_CHECK(alicePub != nullptr);
+ BOOST_CHECK(aliceState.context->publicKeyLen != 0);
+ uint8_t fakePub[] = {0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
+ BOOST_CHECK_THROW(aliceState.deriveSecret(fakePub, sizeof(fakePub)), CryptoError);
+}
+
BOOST_AUTO_TEST_CASE(EcdhWithBase64Key)
{
ECDHState aliceState;