Certificate revocation
Adds the handling of certificate revocation according to ndncert protocol v0.2.
Includes handing on CA module, client module as well as the test cases for these funcationalities.
Currently no internal database are being updated from the revocation.
This actual update and propagation of revocation information needs to relies on a certificate log, which can be attached to the CA module using status update callback.
Change-Id: I21f912285161ce781e17d222e640c8f0c57b50f7
diff --git a/src/ca-detail/ca-sqlite.cpp b/src/ca-detail/ca-sqlite.cpp
index baaf771..7d0444a 100644
--- a/src/ca-detail/ca-sqlite.cpp
+++ b/src/ca-detail/ca-sqlite.cpp
@@ -41,6 +41,7 @@
id INTEGER PRIMARY KEY,
request_id TEXT NOT NULL,
ca_name BLOB NOT NULL,
+ request_type INTEGER NOT NULL,
status INTEGER NOT NULL,
challenge_status TEXT,
cert_key_name BLOB NOT NULL,
@@ -117,7 +118,9 @@
CaSqlite::getRequest(const std::string& requestId)
{
Sqlite3Statement statement(m_database,
- R"_SQLTEXT_(SELECT *
+ R"_SQLTEXT_(SELECT id, request_id, ca_name, status,
+ challenge_status, cert_key_name, cert_request, challenge_type, challenge_secrets,
+ challenge_tp, remaining_tries, remaining_time, request_type, probe_token
FROM CertRequests where request_id = ?)_SQLTEXT_");
statement.bind(1, requestId, SQLITE_TRANSIENT);
@@ -131,11 +134,12 @@
std::string challengeTp = statement.getString(9);
int remainingTries = statement.getInt(10);
int remainingTime = statement.getInt(11);
- CertificateRequest request(caName, requestId, status, challengeStatus, challengeType,
+ int requestType = statement.getInt(12);
+ CertificateRequest request(caName, requestId, requestType, status, challengeStatus, challengeType,
challengeTp, remainingTime, remainingTries,
convertString2Json(challengeSecrets), cert);
- if (statement.getSize(12) != 0) {
- shared_ptr<Data> probeToken = make_shared<Data>(statement.getBlock(12));
+ if (statement.getSize(13) != 0) {
+ shared_ptr<Data> probeToken = make_shared<Data>(statement.getBlock(13));
request.setProbeToken(probeToken);
}
return request;
@@ -171,7 +175,33 @@
m_database,
R"_SQLTEXT_(INSERT INTO CertRequests (request_id, ca_name, status,
challenge_status, cert_key_name, cert_request, challenge_type, challenge_secrets,
- challenge_tp, remaining_tries, remaining_time, probe_token)
+ challenge_tp, remaining_tries, remaining_time, request_type, probe_token)
+ values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?))_SQLTEXT_");
+ statement.bind(1, request.m_requestId, SQLITE_TRANSIENT);
+ statement.bind(2, request.m_caPrefix.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);
+ statement.bind(12, request.m_requestType);
+ statement.bind(13, request.m_probeToken->wireEncode(), SQLITE_TRANSIENT);
+ if (statement.step() != SQLITE_DONE) {
+ BOOST_THROW_EXCEPTION(Error("Request " + request.m_requestId + " cannot be added to database"));
+ }
+ }
+ else {
+ Sqlite3Statement statement(
+ m_database,
+ R"_SQLTEXT_(INSERT INTO CertRequests (request_id, ca_name, status,
+ challenge_status, cert_key_name, cert_request, challenge_type, challenge_secrets,
+ challenge_tp, remaining_tries, remaining_time, request_type)
values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?))_SQLTEXT_");
statement.bind(1, request.m_requestId, SQLITE_TRANSIENT);
statement.bind(2, request.m_caPrefix.wireEncode(), SQLITE_TRANSIENT);
@@ -186,31 +216,7 @@
statement.bind(9, request.m_challengeTp, SQLITE_TRANSIENT);
statement.bind(10, request.m_remainingTries);
statement.bind(11, request.m_remainingTime);
- statement.bind(12, request.m_probeToken->wireEncode(), SQLITE_TRANSIENT);
- if (statement.step() != SQLITE_DONE) {
- BOOST_THROW_EXCEPTION(Error("Request " + request.m_requestId + " cannot be added to database"));
- }
- }
- else {
- Sqlite3Statement statement(
- m_database,
- R"_SQLTEXT_(INSERT INTO CertRequests (request_id, ca_name, status,
- 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_caPrefix.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);
+ statement.bind(12, request.m_requestType);
if (statement.step() != SQLITE_DONE) {
BOOST_THROW_EXCEPTION(Error("Request " + request.m_requestId + " cannot be added to database"));
}
@@ -223,7 +229,7 @@
Sqlite3Statement statement(m_database,
R"_SQLTEXT_(UPDATE CertRequests
SET status = ?, challenge_status = ?, challenge_type = ?, challenge_secrets = ?,
- challenge_tp = ?, remaining_tries = ?, remaining_time = ?
+ challenge_tp = ?, remaining_tries = ?, remaining_time = ?, request_type = ?
WHERE request_id = ?)_SQLTEXT_");
statement.bind(1, request.m_status);
statement.bind(2, request.m_challengeStatus, SQLITE_TRANSIENT);
@@ -232,7 +238,8 @@
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);
+ statement.bind(8, request.m_requestType);
+ statement.bind(9, request.m_requestId, SQLITE_TRANSIENT);
if (statement.step() != SQLITE_DONE) {
addRequest(request);
@@ -243,7 +250,10 @@
CaSqlite::listAllRequests()
{
std::list<CertificateRequest> result;
- Sqlite3Statement statement(m_database, R"_SQLTEXT_(SELECT * FROM CertRequests)_SQLTEXT_");
+ Sqlite3Statement statement(m_database, R"_SQLTEXT_(SELECT id, request_id, ca_name, status,
+ challenge_status, cert_key_name, cert_request, challenge_type, challenge_secrets,
+ challenge_tp, remaining_tries, remaining_time, request_type
+ FROM CertRequests)_SQLTEXT_");
while (statement.step() == SQLITE_ROW) {
std::string requestId = statement.getString(1);
@@ -256,7 +266,8 @@
std::string challengeTp = statement.getString(9);
int remainingTries = statement.getInt(10);
int remainingTime = statement.getInt(11);
- CertificateRequest entry(caName, requestId, status, challengeStatus, challengeType,
+ int requestType = statement.getInt(12);
+ CertificateRequest entry(caName, requestId, requestType, status, challengeStatus, challengeType,
challengeTp, remainingTime, remainingTries,
convertString2Json(challengeSecrets), cert);
result.push_back(entry);
@@ -269,7 +280,10 @@
{
std::list<CertificateRequest> result;
Sqlite3Statement statement(m_database,
- R"_SQLTEXT_(SELECT * FROM CertRequests WHERE ca_name = ?)_SQLTEXT_");
+ R"_SQLTEXT_(SELECT id, request_id, ca_name, status,
+ challenge_status, cert_key_name, cert_request, challenge_type, challenge_secrets,
+ challenge_tp, remaining_tries, remaining_time, request_type
+ FROM CertRequests WHERE ca_name = ?)_SQLTEXT_");
statement.bind(1, caName.wireEncode(), SQLITE_TRANSIENT);
while (statement.step() == SQLITE_ROW) {
@@ -283,7 +297,8 @@
std::string challengeTp = statement.getString(9);
int remainingTries = statement.getInt(10);
int remainingTime = statement.getInt(11);
- CertificateRequest entry(caName, requestId, status, challengeStatus, challengeType,
+ int requestType = statement.getInt(12);
+ CertificateRequest entry(caName, requestId, requestType, status, challengeStatus, challengeType,
challengeTp, remainingTime, remainingTries,
convertString2Json(challengeSecrets), cert);
result.push_back(entry);
diff --git a/src/ca-module.cpp b/src/ca-module.cpp
index 9058c60..5201e31 100644
--- a/src/ca-module.cpp
+++ b/src/ca-module.cpp
@@ -26,6 +26,7 @@
#include "protocol-detail/probe.hpp"
#include "protocol-detail/new.hpp"
#include "protocol-detail/challenge.hpp"
+#include "protocol-detail/revoke.hpp"
#include <ndn-cxx/util/io.hpp>
#include <ndn-cxx/security/verification-helpers.hpp>
#include <ndn-cxx/security/signing-helpers.hpp>
@@ -100,6 +101,10 @@
bind(&CaModule::onChallenge, this, _2));
m_interestFilterHandles.push_back(filterId);
+ // register REVOKE prefix
+ filterId = m_face.setInterestFilter(Name(name).append("REVOKE"),
+ bind(&CaModule::onRevoke, this, _2));
+ m_interestFilterHandles.push_back(filterId);
_LOG_TRACE("Prefix " << name << " got registered");
},
bind(&CaModule::onRegisterFailed, this, _2));
@@ -298,7 +303,7 @@
// create new request instance
std::string requestId = std::to_string(random::generateWord64());
- CertificateRequest certRequest(m_config.m_caPrefix, requestId, STATUS_BEFORE_CHALLENGE, *clientCert);
+ CertificateRequest certRequest(m_config.m_caPrefix, requestId, REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, *clientCert);
try {
m_storage->addRequest(certRequest);
@@ -380,29 +385,43 @@
}
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);
- }
+ if (certRequest.m_requestType == REQUEST_TYPE_NEW) {
+ 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;
+ }
- payload = CHALLENGE::encodeDataPayload(certRequest);
- payload.parse();
- payload.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
- payload.encode();
+ payload = CHALLENGE::encodeDataPayload(certRequest);
+ payload.parse();
+ payload.push_back(makeNestedBlock(tlv_issued_cert_name, issuedCert.getName()));
+ payload.encode();
- //contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
- _LOG_TRACE("Challenge succeeded. Certificate has been issued");
+ //contentJson.add(JSON_CA_CERT_ID, readString(issuedCert.getName().at(-1)));
+ _LOG_TRACE("Challenge succeeded. Certificate has been issued");
+ }
+ else if (certRequest.m_requestType == REQUEST_TYPE_REVOKE) {
+ certRequest.m_status = STATUS_SUCCESS;
+ try {
+ m_storage->deleteRequest(certRequest.m_requestId);
+ _LOG_TRACE("Certificate Revoked");
+ }
+ catch (const std::exception& e) {
+ _LOG_ERROR("Cannot add issued cert and remove the request: " << e.what());
+ return;
+ }
+
+ payload = CHALLENGE::encodeDataPayload(certRequest);
+ payload.parse();
+ _LOG_TRACE("Challenge succeeded. Certificate has been revoked");
+ }
}
else {
try {
@@ -433,6 +452,91 @@
}
}
+void
+CaModule::onRevoke(const Interest& request)
+{
+ // NEW Naming Convention: /<CA-prefix>/CA/REVOKE/[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.");
+ return;
+ }
+ std::string peerKeyBase64 = parameterJson.get(JSON_CLIENT_ECDH, "");
+ if (peerKeyBase64 == "") {
+ _LOG_ERROR("Empty JSON_CLIENT_ECDH obtained from the Interest parameter.");
+ return;
+ }
+
+ // get server's ECDH pub key
+ auto myEcdhPubKeyBase64 = m_ecdh.getBase64PubKey();
+ try {
+ m_ecdh.deriveSecret(peerKeyBase64);
+ }
+ catch (const std::exception& e) {
+ _LOG_ERROR("Cannot derive a shared secret using the provided ECDH key: " << e.what());
+ return;
+ }
+
+ // parse certificate request
+ std::string certRevokeStr = parameterJson.get(JSON_CLIENT_CERT_REVOKE, "");
+ shared_ptr<security::v2::Certificate> clientCert = nullptr;
+ try {
+ std::stringstream ss(certRevokeStr);
+ clientCert = io::load<security::v2::Certificate>(ss);
+ }
+ catch (const std::exception& e) {
+ _LOG_ERROR("Unrecognized revocation request: " << e.what());
+ return;
+ }
+
+ // verify the certificate
+ 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 certificate name " << clientCert->getName());
+ return;
+ }
+ const auto& cert = m_keyChain.getPib().getIdentity(m_config.m_caName).getDefaultKey().getDefaultCertificate();
+ if (!security::verifySignature(*clientCert, cert)) {
+ _LOG_ERROR("Cert request with bad signature.");
+ return;
+ }
+
+ // generate salt for HKDF
+ auto saltInt = random::generateSecureWord64();
+ // hkdf
+ hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
+ (uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
+
+ // create new request instance
+ std::string requestId = std::to_string(random::generateWord64());
+ CertificateRequest certRequest(m_config.m_caName, requestId, REQUEST_TYPE_REVOKE, STATUS_BEFORE_CHALLENGE,
+ *clientCert);
+ try {
+ m_storage->addRequest(certRequest);
+ }
+ catch (const std::exception& e) {
+ _LOG_ERROR("Cannot add new request instance into the storage: " << e.what());
+ return;
+ }
+
+ Data result;
+ result.setName(request.getName());
+ result.setFreshnessPeriod(DEFAULT_DATA_FRESHNESS_PERIOD);
+ result.setContent(REVOKE::encodeDataContent(myEcdhPubKeyBase64,
+ std::to_string(saltInt),
+ certRequest,
+ m_config.m_supportedChallenges));
+ m_keyChain.sign(result, signingByIdentity(m_config.m_caPrefix));
+ m_face.put(result);
+
+ if (m_config.m_statusUpdateCallback) {
+ m_config.m_statusUpdateCallback(certRequest);
+ }
+}
+
+
security::v2::Certificate
CaModule::issueCertificate(const CertificateRequest& certRequest)
{
diff --git a/src/ca-module.hpp b/src/ca-module.hpp
index 7e9c7e6..fad6296 100644
--- a/src/ca-module.hpp
+++ b/src/ca-module.hpp
@@ -90,6 +90,9 @@
onChallenge(const Interest& request);
void
+ onRevoke(const Interest& request);
+
+ void
onRegisterFailed(const std::string& reason);
CertificateRequest
diff --git a/src/certificate-request.cpp b/src/certificate-request.cpp
index 3798ea6..4a4c4b4 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-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -26,21 +26,23 @@
CertificateRequest::CertificateRequest() = default;
-CertificateRequest::CertificateRequest(const Name& caName, const std::string& requestId, int status,
+CertificateRequest::CertificateRequest(const Name& caName, const std::string& requestId, int requestType, int status,
const security::v2::Certificate& cert)
: m_caPrefix(caName)
, m_requestId(requestId)
+ , m_requestType(requestType)
, m_status(status)
, m_cert(cert)
{
}
-CertificateRequest::CertificateRequest(const Name& caName, const std::string& requestId, int status,
+CertificateRequest::CertificateRequest(const Name& caName, const std::string& requestId, int requestType, 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_caPrefix(caName)
, m_requestId(requestId)
+ , m_requestType(requestType)
, m_status(status)
, m_cert(cert)
, m_challengeStatus(challengeStatus)
diff --git a/src/certificate-request.hpp b/src/certificate-request.hpp
index 3ac9948..4c067c5 100644
--- a/src/certificate-request.hpp
+++ b/src/certificate-request.hpp
@@ -32,6 +32,12 @@
typedef boost::property_tree::ptree JsonSection;
+//Request Type Enum
+enum {
+ REQUEST_TYPE_NEW = 0,
+ REQUEST_TYPE_REVOKE = 1
+};
+
/**
* @brief Represents a certificate request instance.
*
@@ -43,8 +49,9 @@
{
public:
CertificateRequest();
- 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,
+ CertificateRequest(const Name& caName, const std::string& requestId, int requestType, int status,
+ const security::v2::Certificate& cert);
+ CertificateRequest(const Name& caName, const std::string& requestId, int requestType, 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);
@@ -55,6 +62,7 @@
public:
Name m_caPrefix;
std::string m_requestId = "";
+ int m_requestType = -1;
int m_status = -1;
security::v2::Certificate m_cert;
std::shared_ptr<Data> m_probeToken = nullptr;
diff --git a/src/client-module.cpp b/src/client-module.cpp
index 697ff8f..1e01dc0 100644
--- a/src/client-module.cpp
+++ b/src/client-module.cpp
@@ -26,6 +26,7 @@
#include "protocol-detail/probe.hpp"
#include "protocol-detail/new.hpp"
#include "protocol-detail/challenge.hpp"
+#include "protocol-detail/revoke.hpp"
#include <ndn-cxx/util/io.hpp>
#include <ndn-cxx/security/signing-helpers.hpp>
#include <ndn-cxx/security/verification-helpers.hpp>
@@ -243,6 +244,68 @@
}
shared_ptr<Interest>
+ClientModule::generateRevokeInterest(const security::v2::Certificate& certificate)
+{
+ // Name requestedName = identityName;
+ bool findCa = false;
+ for (const auto& caItem : m_config.m_caItems) {
+ if (caItem.m_caName.isPrefixOf(certificate.getName())) {
+ m_ca = caItem;
+ findCa = true;
+ }
+ }
+ if (!findCa) { // if cannot find, cannot proceed
+ _LOG_TRACE("Cannot find corresponding CA for the certificate.");
+ return nullptr;
+ }
+
+ // generate Interest packet
+ Name interestName = m_ca.m_caPrefix;
+ interestName.append("CA").append("REVOKE");
+ auto interest = make_shared<Interest>(interestName);
+ interest->setMustBeFresh(true);
+ interest->setCanBePrefix(false);
+ interest->setApplicationParameters(
+ REVOKE::encodeApplicationParameters(m_ecdh.getBase64PubKey(), certificate)
+ );
+
+ // return the Interest packet
+ return interest;
+}
+
+std::list<std::string>
+ClientModule::onRevokeResponse(const Data& reply)
+{
+ 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 contentTLV = reply.getContent();
+ contentTLV.parse();
+
+ // ECDH
+ 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);
+
+ // HKDF
+ hkdf(m_ecdh.context->sharedSecret, m_ecdh.context->sharedSecretLen,
+ (uint8_t*)&saltInt, sizeof(saltInt), m_aesKey, sizeof(m_aesKey));
+
+ // update state
+ m_status = readNonNegativeInteger(contentTLV.get(tlv_status));
+ m_requestId = readString(contentTLV.get(tlv_request_id));
+ m_challengeList.clear();
+ 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 Block& challengeRequest)
{
challengeRequest.parse();
diff --git a/src/client-module.hpp b/src/client-module.hpp
index 46a0a29..f6d706f 100644
--- a/src/client-module.hpp
+++ b/src/client-module.hpp
@@ -108,6 +108,12 @@
shared_ptr<Interest>
generateCertFetchInterest();
+ shared_ptr<Interest>
+ generateRevokeInterest(const security::v2::Certificate& certificate);
+
+ std::list<std::string>
+ onRevokeResponse(const Data& reply);
+
void
onCertFetchResponse(const Data& reply);
diff --git a/src/ndncert-common.hpp b/src/ndncert-common.hpp
index a6a7a04..7b3000f 100644
--- a/src/ndncert-common.hpp
+++ b/src/ndncert-common.hpp
@@ -98,7 +98,8 @@
tlv_issued_cert_name = 169,
tlv_error_code = 171,
tlv_error_info = 173,
- tlv_authentication_tag = 175
+ tlv_authentication_tag = 175,
+ tlv_cert_to_revoke = 177
};
// Parse CA Configuration file
@@ -132,6 +133,7 @@
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";
+const std::string JSON_CLIENT_CERT_REVOKE = "cert-revoke";
// NDNCERT Status Enum
enum {
diff --git a/src/protocol-detail/revoke.cpp b/src/protocol-detail/revoke.cpp
new file mode 100644
index 0000000..5bde720
--- /dev/null
+++ b/src/protocol-detail/revoke.cpp
@@ -0,0 +1,74 @@
+/* -*- 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 "revoke.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
+REVOKE::encodeApplicationParameters(const std::string& ecdhPub, const security::v2::Certificate& certToRevoke)
+{
+ Block request = makeEmptyBlock(tlv::ApplicationParameters);
+ std::stringstream ss;
+ try {
+ security::transform::bufferSource(certToRevoke.wireEncode().wire(), certToRevoke.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_to_revoke, certToRevoke));
+ request.encode();
+ return request;
+}
+
+Block
+REVOKE::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.encode();
+ return response;
+}
+
+} // namespace ndncert
+} // namespace ndn
\ No newline at end of file
diff --git a/src/protocol-detail/revoke.hpp b/src/protocol-detail/revoke.hpp
new file mode 100644
index 0000000..665ed11
--- /dev/null
+++ b/src/protocol-detail/revoke.hpp
@@ -0,0 +1,45 @@
+/* -*- 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_REVOKE_HPP
+#define NDNCERT_PROTOCOL_DETAIL_REVOKE_HPP
+
+#include "../certificate-request.hpp"
+#include "ndn-cxx/encoding/block.hpp"
+#include <ndn-cxx/security/v2/certificate.hpp>
+
+namespace ndn {
+namespace ndncert {
+
+class REVOKE {
+public:
+ static Block
+ encodeApplicationParameters(const std::string& ecdhPub, const security::v2::Certificate& certToRevoke);
+
+ 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_REVOKE_HPP
\ No newline at end of file
diff --git a/tests/unit-tests/ca-memory.t.cpp b/tests/unit-tests/ca-memory.t.cpp
index 7425a0e..a1bcd28 100644
--- a/tests/unit-tests/ca-memory.t.cpp
+++ b/tests/unit-tests/ca-memory.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -82,7 +82,7 @@
auto cert1 = key1.getDefaultCertificate();
// add operation
- CertificateRequest request1(Name("/ndn/site1"), "123", STATUS_BEFORE_CHALLENGE, cert1);
+ CertificateRequest request1(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, cert1);
BOOST_CHECK_NO_THROW(storage.addRequest(request1));
// get operation
@@ -95,7 +95,7 @@
json.put("code", "1234");
// update operation
- CertificateRequest request2(Name("/ndn/site1"), "123", STATUS_CHALLENGE, CHALLENGE_STATUS_SUCCESS,
+ CertificateRequest request2(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_CHALLENGE, CHALLENGE_STATUS_SUCCESS,
"Email", time::toIsoString(time::system_clock::now()), 3600, 3, json, cert1);
storage.updateRequest(request2);
result = storage.getRequest("123");
@@ -106,7 +106,7 @@
auto identity2 = addIdentity(Name("/ndn/site2"));
auto key2 = identity2.getDefaultKey();
auto cert2 = key2.getDefaultCertificate();
- CertificateRequest request3(Name("/ndn/site2"), "456", STATUS_BEFORE_CHALLENGE, cert2);
+ CertificateRequest request3(Name("/ndn/site2"), "456", REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, cert2);
storage.addRequest(request3);
// list operation
diff --git a/tests/unit-tests/ca-module.t.cpp b/tests/unit-tests/ca-module.t.cpp
index cb3cfcd..64a5d7f 100644
--- a/tests/unit-tests/ca-module.t.cpp
+++ b/tests/unit-tests/ca-module.t.cpp
@@ -46,7 +46,7 @@
advanceClocks(time::milliseconds(20), 60);
BOOST_CHECK_EQUAL(ca.m_registeredPrefixHandles.size(), 2);
- BOOST_CHECK_EQUAL(ca.m_interestFilterHandles.size(), 4); // onInfo, onProbe, onNew, onChallenge
+ BOOST_CHECK_EQUAL(ca.m_interestFilterHandles.size(), 5); // onInfo, onProbe, onNew, onChallenge, onRevoke
}
BOOST_AUTO_TEST_CASE(HandleProbe)
@@ -367,7 +367,112 @@
BOOST_CHECK_EQUAL(count, 3);
}
-BOOST_AUTO_TEST_SUITE_END() // TestCaModule
+BOOST_AUTO_TEST_CASE(HandleRevoke)
+{
+ auto identity = addIdentity(Name("/ndn"));
+ auto key = identity.getDefaultKey();
+ auto cert = key.getDefaultCertificate();
+
+ util::DummyClientFace face(io, { true, true });
+ CaModule ca(face, m_keyChain, "tests/unit-tests/ca.conf.test", "ca-storage-memory");
+ advanceClocks(time::milliseconds(20), 60);
+
+ //generate a certificate
+ auto clientIdentity = m_keyChain.createIdentity("/ndn/qwerty");
+ auto clientKey = clientIdentity.getDefaultKey();
+ security::v2::Certificate clientCert;
+ clientCert.setName(Name(clientKey.getName()).append("cert-request").appendVersion());
+ clientCert.setContentType(tlv::ContentType_Key);
+ clientCert.setFreshnessPeriod(time::hours(24));
+ clientCert.setContent(clientKey.getPublicKey().data(), clientKey.getPublicKey().size());
+ SignatureInfo signatureInfo;
+ signatureInfo.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
+ time::system_clock::now() + time::hours(10)));
+ m_keyChain.sign(clientCert, signingByKey(clientKey.getName()).setSignatureInfo(signatureInfo));
+ CertificateRequest certRequest(Name("/ndn"), "122", REQUEST_TYPE_NEW, STATUS_SUCCESS, clientCert);
+ auto issuedCert = ca.issueCertificate(certRequest);
+
+ ClientModule client(m_keyChain);
+ ClientCaItem item;
+ item.m_caName = Name("/ndn");
+ item.m_anchor = cert;
+ client.getClientConf().m_caItems.push_back(item);
+
+ auto interest = client.generateRevokeInterest(issuedCert);
+
+ int count = 0;
+ face.onSendData.connect([&] (const Data& response) {
+ count++;
+ BOOST_CHECK(security::verifySignature(response, cert));
+ auto contentBlock = response.getContent();
+ contentBlock.parse();
+
+ BOOST_CHECK(readString(contentBlock.get(tlv_ecdh_pub)) != "");
+ BOOST_CHECK(readString(contentBlock.get(tlv_salt)) != "");
+ BOOST_CHECK(readString(contentBlock.get(tlv_request_id)) != "");
+
+ auto challengeBlockCount = 0;
+ for (auto const& element : contentBlock.elements()) {
+ if (element.type() == tlv_challenge) {
+ challengeBlockCount++;
+ }
+ }
+
+ BOOST_CHECK(challengeBlockCount != 0);
+
+ client.onRevokeResponse(response);
+ 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);
+
+ advanceClocks(time::milliseconds(20), 60);
+ BOOST_CHECK_EQUAL(count, 1);
+}
+
+BOOST_AUTO_TEST_CASE(HandleRevokeWithBadCert)
+{
+ auto identity = addIdentity(Name("/ndn"));
+ auto key = identity.getDefaultKey();
+ auto cert = key.getDefaultCertificate();
+
+ util::DummyClientFace face(io, { true, true });
+ CaModule ca(face, m_keyChain, "tests/unit-tests/ca.conf.test", "ca-storage-memory");
+ advanceClocks(time::milliseconds(20), 60);
+
+ //generate a certificate
+ auto clientIdentity = m_keyChain.createIdentity("/ndn/qwerty");
+ auto clientKey = clientIdentity.getDefaultKey();
+ security::v2::Certificate clientCert;
+ clientCert.setName(Name(clientKey.getName()).append("NDNCERT").append(std::to_string(1473283247810732701)));
+ clientCert.setContentType(tlv::ContentType_Key);
+ clientCert.setFreshnessPeriod(time::hours(24));
+ clientCert.setContent(clientKey.getPublicKey().data(), clientKey.getPublicKey().size());
+ SignatureInfo signatureInfo;
+ signatureInfo.setValidityPeriod(security::ValidityPeriod(time::system_clock::now(),
+ time::system_clock::now() + time::hours(10)));
+ m_keyChain.sign(clientCert, signingByKey(clientKey.getName()).setSignatureInfo(signatureInfo));
+
+ ClientModule client(m_keyChain);
+ ClientCaItem item;
+ item.m_caName = Name("/ndn");
+ item.m_anchor = cert;
+ client.getClientConf().m_caItems.push_back(item);
+
+ auto interest = client.generateRevokeInterest(clientCert);
+
+ int count = 0;
+ face.onSendData.connect([&] (const Data& response) {
+ count++;
+ });
+ face.receive(*interest);
+
+ advanceClocks(time::milliseconds(20), 60);
+ BOOST_CHECK_EQUAL(count, 0);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END() // TestCaModule
} // namespace tests
} // namespace ndncert
diff --git a/tests/unit-tests/ca-sqlite.t.cpp b/tests/unit-tests/ca-sqlite.t.cpp
index 07782a6..aa70f3a 100644
--- a/tests/unit-tests/ca-sqlite.t.cpp
+++ b/tests/unit-tests/ca-sqlite.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -81,7 +81,7 @@
auto cert1 = key1.getDefaultCertificate();
// add operation
- CertificateRequest request1(Name("/ndn/site1"), "123", STATUS_BEFORE_CHALLENGE, cert1);
+ CertificateRequest request1(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, cert1);
BOOST_CHECK_NO_THROW(storage.addRequest(request1));
// get operation
@@ -93,7 +93,7 @@
// update operation
JsonSection json;
json.put("test", "4567");
- CertificateRequest request2(Name("/ndn/site1"), "123", STATUS_CHALLENGE, CHALLENGE_STATUS_SUCCESS,
+ CertificateRequest request2(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_CHALLENGE, CHALLENGE_STATUS_SUCCESS,
"Email", time::toIsoString(time::system_clock::now()), 3600, 3, json, cert1);
storage.updateRequest(request2);
result = storage.getRequest("123");
@@ -104,7 +104,7 @@
auto identity2 = addIdentity(Name("/ndn/site2"));
auto key2 = identity2.getDefaultKey();
auto cert2 = key2.getDefaultCertificate();
- CertificateRequest request3(Name("/ndn/site2"), "456", STATUS_BEFORE_CHALLENGE, cert2);
+ CertificateRequest request3(Name("/ndn/site2"), "456", REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, cert2);
storage.addRequest(request3);
// list operation
diff --git a/tests/unit-tests/challenge-credential.t.cpp b/tests/unit-tests/challenge-credential.t.cpp
index 2b8e9b2..3472687 100644
--- a/tests/unit-tests/challenge-credential.t.cpp
+++ b/tests/unit-tests/challenge-credential.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -55,7 +55,7 @@
auto identityA = addIdentity(Name("/example"));
auto keyA = identityA.getDefaultKey();
auto certA = key.getDefaultCertificate();
- CertificateRequest request(Name("/example"), "123", STATUS_BEFORE_CHALLENGE, certA);
+ CertificateRequest request(Name("/example"), "123", REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, certA);
// create requester's existing cert
auto identityB = addIdentity(Name("/trust/cert"));
diff --git a/tests/unit-tests/challenge-email.t.cpp b/tests/unit-tests/challenge-email.t.cpp
index 8ff47c4..50e30c5 100644
--- a/tests/unit-tests/challenge-email.t.cpp
+++ b/tests/unit-tests/challenge-email.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -45,7 +45,7 @@
auto identity = addIdentity(Name("/ndn/site1"));
auto key = identity.getDefaultKey();
auto cert = key.getDefaultCertificate();
- CertificateRequest request(Name("/ndn/site1"), "123", STATUS_BEFORE_CHALLENGE, cert);
+ CertificateRequest request(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, cert);
Block paramTLV = makeEmptyBlock(tlv_encrypted_payload);
paramTLV.push_back(makeStringBlock(tlv_parameter_key, ChallengeEmail::JSON_EMAIL));
@@ -95,7 +95,7 @@
auto identity = addIdentity(Name("/ndn/site1"));
auto key = identity.getDefaultKey();
auto cert = key.getDefaultCertificate();
- CertificateRequest request(Name("/ndn/site1"), "123", STATUS_BEFORE_CHALLENGE, cert);
+ CertificateRequest request(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, cert);
Block paramTLV = makeEmptyBlock(tlv_encrypted_payload);
paramTLV.push_back(makeStringBlock(tlv_parameter_key, ChallengeEmail::JSON_EMAIL));
@@ -115,7 +115,7 @@
auto cert = key.getDefaultCertificate();
JsonSection json;
json.put(ChallengeEmail::JSON_CODE, "4567");
- CertificateRequest request(Name("/ndn/site1"), "123", STATUS_CHALLENGE, ChallengeEmail::NEED_CODE,
+ CertificateRequest request(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_CHALLENGE, ChallengeEmail::NEED_CODE,
"Email", time::toIsoString(time::system_clock::now()), 3600, 3, json, cert);
Block paramTLV = makeEmptyBlock(tlv_encrypted_payload);
@@ -137,7 +137,7 @@
auto cert = key.getDefaultCertificate();
JsonSection json;
json.put(ChallengeEmail::JSON_CODE, "4567");
- CertificateRequest request(Name("/ndn/site1"), "123", STATUS_CHALLENGE, ChallengeEmail::NEED_CODE,
+ CertificateRequest request(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_CHALLENGE, ChallengeEmail::NEED_CODE,
"email", time::toIsoString(time::system_clock::now()), 3600, 3, json, cert);
Block paramTLV = makeEmptyBlock(tlv_encrypted_payload);
diff --git a/tests/unit-tests/challenge-pin.t.cpp b/tests/unit-tests/challenge-pin.t.cpp
index a1fea0d..9cabf38 100644
--- a/tests/unit-tests/challenge-pin.t.cpp
+++ b/tests/unit-tests/challenge-pin.t.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -38,7 +38,7 @@
auto identity = addIdentity(Name("/ndn/site1"));
auto key = identity.getDefaultKey();
auto cert = key.getDefaultCertificate();
- CertificateRequest request(Name("/ndn/site1"), "123", STATUS_BEFORE_CHALLENGE, cert);
+ CertificateRequest request(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_BEFORE_CHALLENGE, cert);
ChallengePin challenge;
challenge.handleChallengeRequest(makeEmptyBlock(tlv_encrypted_payload), request);
@@ -55,7 +55,7 @@
auto cert = key.getDefaultCertificate();
JsonSection secret;
secret.add(ChallengePin::JSON_PIN_CODE, "12345");
- CertificateRequest request(Name("/ndn/site1"), "123", STATUS_CHALLENGE, ChallengePin::NEED_CODE, "pin",
+ CertificateRequest request(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_CHALLENGE, ChallengePin::NEED_CODE, "pin",
time::toIsoString(time::system_clock::now()), 3600, 3, secret, cert);
Block paramTLV = makeEmptyBlock(tlv_encrypted_payload);
@@ -77,7 +77,7 @@
auto cert = key.getDefaultCertificate();
JsonSection secret;
secret.add(ChallengePin::JSON_PIN_CODE, "12345");
- CertificateRequest request(Name("/ndn/site1"), "123", STATUS_CHALLENGE, ChallengePin::NEED_CODE, "pin",
+ CertificateRequest request(Name("/ndn/site1"), "123", REQUEST_TYPE_NEW, STATUS_CHALLENGE, ChallengePin::NEED_CODE, "pin",
time::toIsoString(time::system_clock::now()), 3600, 3, secret, cert);
Block paramTLV = makeEmptyBlock(tlv_encrypted_payload);
diff --git a/tools/ndncert-ca-server.cpp b/tools/ndncert-ca-server.cpp
index 8aaf59b..10d6a6f 100644
--- a/tools/ndncert-ca-server.cpp
+++ b/tools/ndncert-ca-server.cpp
@@ -83,7 +83,7 @@
if (wantRepoOut) {
ca.setStatusUpdateCallback([&] (const CertificateRequest& request) {
- if (request.m_status == STATUS_SUCCESS) {
+ if (request.m_status == STATUS_SUCCESS && request.m_requestType == REQUEST_TYPE_NEW) {
auto issuedCert = request.m_cert;
boost::asio::ip::tcp::iostream requestStream;
#if BOOST_VERSION >= 106700
diff --git a/tools/ndncert-ca-status.cpp b/tools/ndncert-ca-status.cpp
index 7438dc6..ecfc9c6 100644
--- a/tools/ndncert-ca-status.cpp
+++ b/tools/ndncert-ca-status.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/**
- * Copyright (c) 2017-2019, Regents of the University of California.
+ * Copyright (c) 2017-2020, Regents of the University of California.
*
* This file is part of ndncert, a certificate management system based on NDN.
*
@@ -76,6 +76,7 @@
for (const auto& entry : requestList) {
std::cerr << "Request ID: " << entry.m_requestId << "\t"
+ << "Request Type" << entry.m_requestType << "\t"
<< "Current Status: " << entry.m_status << std::endl
<< "Applying CA: " << entry.m_caPrefix << std::endl
<< "Applying for key: " << entry.m_cert.getName() << std::endl
diff --git a/tools/ndncert-client.cpp b/tools/ndncert-client.cpp
index f7bd7b0..0073521 100644
--- a/tools/ndncert-client.cpp
+++ b/tools/ndncert-client.cpp
@@ -38,7 +38,7 @@
int nStep;
Face face;
-security::KeyChain keyChain;
+security::v2::KeyChain keyChain;
std::string challengeType;
int validityPeriod = -1;
ClientModule client(keyChain);